Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

storing/loading complex numbers in text form...

72 views
Skip to first unread message

Chris M. Thomasson

unread,
Jun 2, 2017, 7:27:31 PM6/2/17
to
Fwiw, here is a little program that does this. It stores complex numbers
in ctxt.bin, then loads them all back:
________________________
#include <complex.h>
#include <tgmath.h>
#include <stdlib.h>
#include <stdio.h>


#define CT_PREC ".13"
#define CT_OFL "%" CT_PREC "lf"
typedef double complex ct_complex;


void
ct_load_ctxt(
FILE* in_file,
ct_complex* buf,
size_t buf_size
) {
printf("LOAD:\n");

for (size_t i = 0; i < buf_size; ++i)
{
double real_part = 0;
double imag_part = 0;

int r = fscanf(in_file, "(%lf, %lf) ", &real_part, &imag_part);
if (r != 2) break;

buf[i] = real_part+imag_part*I;

printf("%lu:(" CT_OFL ", " CT_OFL ")\n",
(unsigned long)i, creal(buf[i]), cimag(buf[i]));
}
}

void
ct_store_ctxt(
FILE* out_file,
ct_complex* buf,
size_t buf_size
) {
printf("STORE:\n");

for (size_t i = 0; i < buf_size; ++i)
{
fprintf(out_file,
"(" CT_OFL ", " CT_OFL ") ", creal(buf[i]), cimag(buf[i]));

printf("%lu:(" CT_OFL ", " CT_OFL ")\n",
(unsigned long)i, creal(buf[i]), cimag(buf[i]));
}
}


int main(void)
{
char const* in_file = "ctxt.bin";

ct_complex ct[] = {
-2.123+4.56789*I,
2.456-4.876*I,
-2.789+4.543*I,
2.101112-4.210*I,
123.456+789.101113*I
};

size_t ct_size = sizeof(ct) / sizeof(ct_complex);


// STORE
{
char const* out_file = in_file;

FILE* fout = fopen(out_file, "w");

ct_store_ctxt(fout, ct, ct_size);

fclose(fout);
}

printf("________________________________\n");

// LOAD
{
FILE* fin = fopen(in_file, "r");

ct_load_ctxt(fin, ct, ct_size);

fclose(fin);
}

return 0;
}
________________________

I need this to store complex numbers as a fractal ciphertext in an
experimental encryption I am developing.

Can you find any crap in here?

Ben Bacarisse

unread,
Jun 2, 2017, 7:42:53 PM6/2/17
to
"Chris M. Thomasson" <inv...@invalid.invalid> writes:

> Fwiw, here is a little program that does this. It stores complex
> numbers in ctxt.bin, then loads them all back:

If you have a modern sprintf/fscanf consider using the %a format. If
you don't give a precision, and the floating radix is a power of 2
(very likely) then the representation will be exact.

> void
> ct_load_ctxt(
> FILE* in_file,
> ct_complex* buf,
> size_t buf_size
> ) {
> printf("LOAD:\n");
>
> for (size_t i = 0; i < buf_size; ++i)

I find this misleading. I prefer to write the loop condition
explicitly:

while (fscanf(in_file, "(%la, %la) ", &real_part, &imag_part) == 2 &&
i < buf_size) ...

but in know that's now considered very Algol and so last century!

<snip>
--
Ben.

Chris M. Thomasson

unread,
Jun 3, 2017, 4:53:56 PM6/3/17
to
On 6/2/2017 4:42 PM, Ben Bacarisse wrote:
> "Chris M. Thomasson" <inv...@invalid.invalid> writes:
>
>> Fwiw, here is a little program that does this. It stores complex
>> numbers in ctxt.bin, then loads them all back:
>
> If you have a modern sprintf/fscanf consider using the %a format. If
> you don't give a precision, and the floating radix is a power of 2
> (very likely) then the representation will be exact.
>
>> void
>> ct_load_ctxt(
>> FILE* in_file,
>> ct_complex* buf,
>> size_t buf_size
>> ) {
>> printf("LOAD:\n");
>>
>> for (size_t i = 0; i < buf_size; ++i)
>
> I find this misleading. I prefer to write the loop condition
> explicitly:
>
> while (fscanf(in_file, "(%la, %la) ", &real_part, &imag_part) == 2 &&
> i < buf_size) ...

Well, it does get rid of that break in the loop. Just remember to
increment i.

> but in know that's now considered very Algol and so last century!

;^)



Tim Rentsch

unread,
Jun 5, 2017, 4:02:05 PM6/5/17
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:

> "Chris M. Thomasson" <inv...@invalid.invalid> writes:
>
> [...]
>
>> void
>> ct_load_ctxt(
>> FILE* in_file,
>> ct_complex* buf,
>> size_t buf_size
>> ) {
>> printf("LOAD:\n");
>>
>> for (size_t i = 0; i < buf_size; ++i)
>
> I find this misleading. I prefer to write the loop condition
> explicitly:
>
> while (fscanf(in_file, "(%la, %la) ", &real_part, &imag_part) == 2 &&
> i < buf_size) ...

I expect you would prefer even more to put the 'i' comparison
test first:

while (i < buf_size && fscanf(...) == 2) ...

Tim Rentsch

unread,
Jun 5, 2017, 4:37:39 PM6/5/17
to
"Chris M. Thomasson" <inv...@invalid.invalid> writes:

I won't say crap but I do have some suggestions.

In several places you have variable names ending in '_size' that
are not sizes. I suggest '_limit' or '_extent' instead.

The symbol CT_OFL is used two times in each of three places,
always in the same pattern. The common pattern can be factored,
eg,

#define CT_PAIR "(" CT_OFL ", " CT_OFL ")"

which will simplify the printf()/fprintf() calls that use it.

Probably the most important suggestion: ou can make the code a
lot simpler if you use a union for the complex values, as for
example

typedef { double complex z; double d[2]; } ct_complex;

See how this change simplifies the load/store routines:

void
ct_load_ctxt( FILE* in_file, ct_complex* buf, size_t buf_extent ){
printf( "LOAD:\n" );

for( size_t i = 0; i < buf_extent; ++i ){
int r = fscanf( in_file, "(%lf, %lf) ", &buf[i].d[0], &buf[i].d[1] );
if( r != 2 ) break;

printf( "%zu:" CT_PAIR "\n", i, buf[i].d[0], buf[i].d[1] );
}
}

void
ct_store_ctxt( FILE* out_file, ct_complex* buf, size_t buf_extent ){
printf( "STORE:\n" );

for( size_t i = 0; i < buf_extent; ++i ){
fprintf( out_file, CT_PAIR " ", buf[i].d[0], buf[i].d[1] );

printf( "%zu:" CT_PAIR "\n", i, buf[i].d[0], buf[i].d[1] );
}
}

To put your mind at ease, the overlap of the two doubles and the
complex type is guaranteed by the Standard.

Incidentally, having that union type means you can define the 'I'
macro yourself if you want:

#define I ((ct_complex){ .d = { 0, 1 } }.z)


Putting all that together, plus a couple other minor items, here
is the resulting revised full program:

#include <stdio.h>

#define CT_PREC ".13"
#define CT_OFL "%" CT_PREC "lf"
#define CT_PAIR "(" CT_OFL ", " CT_OFL ")"
typedef union { _Complex double z; double d[2]; } ct_complex;
#define I ((ct_complex){ .d = { 0, 1 } }.z)


void
ct_load_ctxt( FILE* in_file, ct_complex* buf, size_t buf_extent ){
printf( "LOAD:\n" );

for( size_t i = 0; i < buf_extent; ++i ){
int r = fscanf( in_file, "(%lf, %lf) ", &buf[i].d[0], &buf[i].d[1] );
if( r != 2 ) break;

printf( "%zu:" CT_PAIR "\n", i, buf[i].d[0], buf[i].d[1] );
}
}

void
ct_store_ctxt( FILE* out_file, ct_complex* buf, size_t buf_extent ){
printf( "STORE:\n" );

for( size_t i = 0; i < buf_extent; ++i ){
fprintf( out_file, CT_PAIR " ", buf[i].d[0], buf[i].d[1] );

printf( "%zu:" CT_PAIR "\n", i, buf[i].d[0], buf[i].d[1] );
}
}


void
store_complex_array( size_t n, ct_complex buf[n], const char *filename ){
FILE* fout = fopen( filename, "w" );
ct_store_ctxt( fout, buf, n );
fclose( fout );
}

void
load_complex_array( size_t n, ct_complex buf[n], const char *filename ){
FILE* fin = fopen( filename, "r" );
ct_load_ctxt( fin, buf, n );
fclose( fin );
}


int
main( void ){
char const* in_file = "/tmp/ctxt.bin";

ct_complex ct[] = {
-2.123 + 4.56789*I,
2.456 - 4.876*I,
-2.789 + 4.543*I,
2.101112 - 4.210*I,
123.456 + 789.101113*I
};

size_t ct_extent = sizeof(ct) / sizeof(ct_complex);
store_complex_array( ct_extent, ct, in_file );
printf( "________________________________\n" );
load_complex_array( ct_extent, ct, in_file );

return 0;
}

Chris M. Thomasson

unread,
Jun 5, 2017, 5:39:22 PM6/5/17
to
On 6/5/2017 1:37 PM, Tim Rentsch wrote:
> "Chris M. Thomasson" <inv...@invalid.invalid> writes:
>
>> Fwiw, here is a little program that does this. It stores complex
>> numbers in ctxt.bin, then loads them all back:
>> ________________________
[...]
>> ________________________
>>
>> I need this to store complex numbers as a fractal ciphertext in an
>> experimental encryption I am developing.
>>
>> Can you find any crap in here?
>
> I won't say crap but I do have some suggestions.
>
> In several places you have variable names ending in '_size' that
> are not sizes. I suggest '_limit' or '_extent' instead.

Okay. How about _max?


> The symbol CT_OFL is used two times in each of three places,
> always in the same pattern. The common pattern can be factored,
> eg,
>
> #define CT_PAIR "(" CT_OFL ", " CT_OFL ")"
>
> which will simplify the printf()/fprintf() calls that use it.

Agreed. It will greatly simplify the calls.


> Probably the most important suggestion: ou can make the code a
> lot simpler if you use a union for the complex values, as for
> example
>
> typedef { double complex z; double d[2]; } ct_complex;
>
> See how this change simplifies the load/store routines:
>
> void
> ct_load_ctxt( FILE* in_file, ct_complex* buf, size_t buf_extent ){
> printf( "LOAD:\n" );
>
> for( size_t i = 0; i < buf_extent; ++i ){
> int r = fscanf( in_file, "(%lf, %lf) ", &buf[i].d[0], &buf[i].d[1] );
> if( r != 2 ) break;
>
> printf( "%zu:" CT_PAIR "\n", i, buf[i].d[0], buf[i].d[1] );
> }
> }
>
> void
> ct_store_ctxt( FILE* out_file, ct_complex* buf, size_t buf_extent ){
> printf( "STORE:\n" );
>
> for( size_t i = 0; i < buf_extent; ++i ){
> fprintf( out_file, CT_PAIR " ", buf[i].d[0], buf[i].d[1] );
>
> printf( "%zu:" CT_PAIR "\n", i, buf[i].d[0], buf[i].d[1] );
> }
> }
>
> To put your mind at ease, the overlap of the two doubles and the
> complex type is guaranteed by the Standard.

Oh wow. I did not know that this was legal! Thank you so much for the
wonderful suggestion. It allows for algorithms to index the real and
imaginary parts directly, and gets rid of the creal/imag calls. Much
more flexible indeed.


> Incidentally, having that union type means you can define the 'I'
> macro yourself if you want:
>
> #define I ((ct_complex){ .d = { 0, 1 } }.z)

Ditto. Very helpful when one wants to see what happens if I is not 1.
Thank you for the code: it does look cleaner to me.

:^)

Ben Bacarisse

unread,
Jun 5, 2017, 6:36:09 PM6/5/17
to
Yes, thanks. That was indeed my intent but something happened between
brain and Internet.

--
Ben.

Tim Rentsch

unread,
Jun 6, 2017, 5:58:14 AM6/6/17
to
"Chris M. Thomasson" <inv...@invalid.invalid> writes:

> On 6/5/2017 1:37 PM, Tim Rentsch wrote:
>> "Chris M. Thomasson" <inv...@invalid.invalid> writes:
>>
>>> Fwiw, here is a little program that does this. It stores complex
>>> numbers in ctxt.bin, then loads them all back:
>>> ________________________
>
> [...]
>
>>> ________________________
>>>
>>> I need this to store complex numbers as a fractal ciphertext in an
>>> experimental encryption I am developing.
>>>
>>> Can you find any crap in here?
>>
>> I won't say crap but I do have some suggestions.
>>
>> In several places you have variable names ending in '_size' that
>> are not sizes. I suggest '_limit' or '_extent' instead.
>
> Okay. How about _max?

I think _max is misleading: the name suggests the maximum index
value, but what is needed is the maximum index value + 1. I
believe _extent is the most proper: it has a good historical
pedigree, and agrees with 'std::extent' in C++ <type_traits>.
If you don't like _extent, _limit is a good alternative (and
which I will admit is my personal preference, but don't pay
attention to that).


>> Probably the most important suggestion: ou can make the code a
>> lot simpler if you use a union for the complex values, as for
>> example
>>
>> typedef { double complex z; double d[2]; } ct_complex;
>>[...]
>>
>> Incidentally, having that union type means you can define the 'I'
>> macro yourself if you want:
>>
>> #define I ((ct_complex){ .d = { 0, 1 } }.z)

Here I should correct myself. First, the 'I' macro should use
'float' rather than 'double':

#define I ((union { float f[2]; _Complex float z; }){{0,1}}.z)

to avoid unwanted promotions.

Second, strictly speaking this definition of 'I' might not be a
replacement for the 'I' in <complex.h>. The reason is the
Standard allows (but does not require!) a purely imaginary type
modifier '_Imaginary', and if an implementation supports
imaginary types then 'I' is an imaginary type rather than a
complex type. I doubt this possibility makes any difference
in practice, but for completeness it should be mentioned.


> Thank you [...]

You are most welcome sir. It's always nice to get an
appreciative response. :)

GOTHIER Nathan

unread,
Jun 6, 2017, 7:23:54 AM6/6/17
to
On Fri, 2 Jun 2017 16:27:22 -0700
"Chris M. Thomasson" <inv...@invalid.invalid> wrote:

> Fwiw, here is a little program that does this. It stores complex numbers
> in ctxt.bin, then loads them all back:
> ...
> I need this to store complex numbers as a fractal ciphertext in an
> experimental encryption I am developing.
>
> Can you find any crap in here?

At first sight, I just don't like the code style (inconsistent functions).

I would write the prototypes as:

typedef double complex dblc_t;

int cfscan(FILE *stream, dblc_t *buf, size_t n);
int cfprint(FILE *stream, dblc_t *buf, size_t n);

I prefer short but clear names with a touch of C spirit. The return type and
the function identifier are usually on the same line. In addition, the function
body start on a new line.

Chris M. Thomasson

unread,
Jun 6, 2017, 4:06:35 PM6/6/17
to
Fair enough. Fwiw, one of the reasons I use multi-line function
definitions/declarations was back when I was creating DLL's:

http://webpages.charter.net/appcore/appcore/include/cpu/i686/ac_i686_h.html

AC_APIEXPORT ac_i686_node_t* AC_APIDECL
ac_i686_node_cache_pop
( const void *state );

If this was all on one line, well, that is a bit too much for me. Also,
it seems to separate things. Wrt the long function names, well, I was so
used to POSIX threads that I just did not give it a second thought.
Verbose functions like:

pthread_mutex_trylock

are fine with me.

Chris M. Thomasson

unread,
Jun 16, 2017, 1:20:49 AM6/16/17
to
No problem. I agree with you wrt _max being misleading. _extent is
better Sir! Thank you for taking the time to help me out.

Btw, I have always liked your posts. Quite informative indeed!

:^D
0 new messages