Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #158393 > unrolled thread
| Started by | beej@beej.us (Beej) |
|---|---|
| First post | 2021-01-16 06:27 +0000 |
| Last post | 2021-01-27 07:30 -0800 |
| Articles | 14 — 4 participants |
Back to article view | Back to comp.lang.c
CMPLX vs a+bi values beej@beej.us (Beej) - 2021-01-16 06:27 +0000
Re: CMPLX vs a+bi values James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-01-16 11:18 -0500
Re: CMPLX vs a+bi values "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-01-20 13:52 -0800
Re: CMPLX vs a+bi values "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-01-20 14:01 -0800
Re: CMPLX vs a+bi values Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-01-20 07:20 -0800
Re: CMPLX vs a+bi values beej@beej.us (Beej) - 2021-01-26 02:13 +0000
Re: CMPLX vs a+bi values Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-01-27 06:19 -0800
Re: CMPLX vs a+bi values "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-01-20 13:39 -0800
Re: CMPLX vs a+bi values "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-01-20 13:40 -0800
Re: CMPLX vs a+bi values James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-01-20 17:40 -0500
Re: CMPLX vs a+bi values "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-01-20 14:57 -0800
Re: CMPLX vs a+bi values James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-01-20 19:21 -0500
Re: CMPLX vs a+bi values "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-01-20 19:44 -0800
Re: CMPLX vs a+bi values Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-01-27 07:30 -0800
| From | beej@beej.us (Beej) |
|---|---|
| Date | 2021-01-16 06:27 +0000 |
| Subject | CMPLX vs a+bi values |
| Message-ID | <rtu0vv$h9q$1@dont-email.me> |
Time for another esoteric question! ---------- #include <complex.h> double complex a = CMPLX(1, 2); double complex b = 1 + 2*I; ---------- They compare equal, of course. Are there any differences between the two values, i.e. whether or not CMPLX() is used? Right before posting, another search took me here: https://en.cppreference.com/w/c/numeric/complex/Imaginary_I Where they write of _Imaginary_I: > This macro allows for the precise way to assemble a complex number > from its real and imaginary components, e.g. with (double > complex)((double)x + _Imaginary_I * (double)y). This pattern was > standardized in C11 as the macro CMPLX. Note that if _Complex_I is > used instead, this expression is allowed to convert negative zero to > positive zero in the imaginary position. And in C11 7.3.9.3p4: > NOTE These macros act as if the implementation supported imaginary > types and the definitions were: > > #define CMPLX(x, y) ((double complex)((double)(x) + \ > _Imaginary_I * (double)(y))) calling out _Imaginary_I explicitly. So maybe on an implementation where I is _Complex_I, a non-CMPLX complex value might be allowed to convert a negative zero to positive--in contrast to a CMPLX()-created value...? More implications in C11 7.3.3 (Branch Cuts). Am I on the right track? -Beej
[toc] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2021-01-16 11:18 -0500 |
| Message-ID | <rtv3l8$9of$1@dont-email.me> |
| In reply to | #158393 |
On 1/16/21 1:27 AM, Beej wrote: > Time for another esoteric question! > > ---------- > > #include <complex.h> > > double complex a = CMPLX(1, 2); > double complex b = 1 + 2*I; > > ---------- > > They compare equal, of course. > > Are there any differences between the two values, i.e. whether or not > CMPLX() is used? In principle, unfortunately, yes, but not because of your use of CMPLX(). "The accuracy of the floating-point operations (+, -, *, /) and of the library functions in <math.h> and <complex.h> that return floating-point results is implementation-defined, as is the accuracy of the conversion between floating-point internal representations and string representations performed by the library functions in <stdio.h>, <stdlib.h>, and <wchar.h>. The implementation may state that the accuracy is unknown." (5.2.4.2.2p6). In principle, this means that an implementation would be within its rights to implement subtraction so inaccurately that LDBL_EPSILON - LDBL_MAX > LDBL_MAX - LDBL_EPSILON evaluate to true. If __STDC_IEC_599__ is pre#defined by the implementation, then the optional requirements specified in Annex F are met, which means that many requirements of IEC 60559 (== ANSI/ISEE 754) apply, including pretty much the strongest accuracy requirements that it is feasible to mandate for floating point math. That's good enough to prohibit my example from failing, but it's still lenient enough to allow identical floating point expressions with no side effects to have results that are not equal.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2021-01-20 13:52 -0800 |
| Message-ID | <rua8mo$1mmi$1@gioia.aioe.org> |
| In reply to | #158396 |
On 1/16/2021 8:18 AM, James Kuyper wrote: > On 1/16/21 1:27 AM, Beej wrote: >> Time for another esoteric question! >> >> ---------- >> >> #include <complex.h> >> >> double complex a = CMPLX(1, 2); >> double complex b = 1 + 2*I; >> >> ---------- >> >> They compare equal, of course. >> >> Are there any differences between the two values, i.e. whether or not >> CMPLX() is used? > > In principle, unfortunately, yes, but not because of your use of CMPLX(). > > "The accuracy of the floating-point operations (+, -, *, /) and of the > library functions in <math.h> and <complex.h> that return floating-point > results is implementation-defined, as is the accuracy of the conversion > between floating-point internal representations and string > representations performed by the library functions in <stdio.h>, > <stdlib.h>, and <wchar.h>. The implementation may state that the > accuracy is unknown." (5.2.4.2.2p6). > > In principle, this means that an implementation would be within its > rights to implement subtraction so inaccurately that > LDBL_EPSILON - LDBL_MAX > LDBL_MAX - LDBL_EPSILON > evaluate to true. > > If __STDC_IEC_599__ is pre#defined by the implementation, then the > optional requirements specified in Annex F are met, which means that > many requirements of IEC 60559 (== ANSI/ISEE 754) apply, including > pretty much the strongest accuracy requirements that it is feasible to > mandate for floating point math. That's good enough to prohibit my > example from failing, but it's still lenient enough to allow identical > floating point expressions with no side effects to have results that are > not equal. > Ohhh yeah. Check this out... A way to store real data in the roots of complex numbers. It suffers from accumulating floating point errors in the form of data loss when one tries to store "too much" data. Then again, it depends on the data itself. Sometimes, my experiment can actually compress things, strange: https://groups.google.com/g/comp.lang.c++/c/bB1wA4wvoFc/m/OTccTiXLAgAJ Pure C99: https://github.com/ChrisMThomasson/fractal_cipher/blob/master/RIFC/cpp/ct_rifc_sample.cpp
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2021-01-20 14:01 -0800 |
| Message-ID | <rua97o$1t87$1@gioia.aioe.org> |
| In reply to | #158512 |
On 1/20/2021 1:52 PM, Chris M. Thomasson wrote: > On 1/16/2021 8:18 AM, James Kuyper wrote: [...] > Pure C99: Damn it! The following is in C++. Sorry. Facepalm. > > https://github.com/ChrisMThomasson/fractal_cipher/blob/master/RIFC/cpp/ct_rifc_sample.cpp >
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-01-20 07:20 -0800 |
| Message-ID | <86h7nbocsh.fsf@linuxsc.com> |
| In reply to | #158393 |
beej@beej.us (Beej) writes: > Time for another esoteric question! > > ---------- > > #include <complex.h> > > double complex a = CMPLX(1, 2); > double complex b = 1 + 2*I; > > ---------- > > They compare equal, of course. > > Are there any differences between the two values, i.e. whether or > not CMPLX() is used? [...] I have some comments on this question. First though I am curious to know if you read my response to your question about floodfill.
[toc] | [prev] | [next] | [standalone]
| From | beej@beej.us (Beej) |
|---|---|
| Date | 2021-01-26 02:13 +0000 |
| Message-ID | <runtsh$e72$1@dont-email.me> |
| In reply to | #158482 |
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote: > I have some comments on this question. First though I am > curious to know if you read my response to your question > about floodfill. I did; I just didn't have anything additional to add. -Beej
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-01-27 06:19 -0800 |
| Message-ID | <86sg6mlaxx.fsf@linuxsc.com> |
| In reply to | #158620 |
beej@beej.us (Beej) writes: > Tim Rentsch <tr.17687@z991.linuxsc.com> wrote: > >> I have some comments on this question. First though I am >> curious to know if you read my response to your question >> about floodfill. > > I did; I just didn't have anything additional to add. I wasn't sure what your reactions were or even if you had read it at all. I went to some amount of effort to put a response together, so normally I would expect to see at least an acknowledgement, and a bit more if any of the response was new to you. Just to say that directly.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2021-01-20 13:39 -0800 |
| Message-ID | <rua7ue$1c1u$1@gioia.aioe.org> |
| In reply to | #158393 |
On 1/15/2021 10:27 PM, Beej wrote: > Time for another esoteric question! > > ---------- > > #include <complex.h> > > double complex a = CMPLX(1, 2); > double complex b = 1 + 2*I; > > ---------- > > They compare equal, of course. > > Are there any differences between the two values, i.e. whether or not > CMPLX() is used? [...] Well, CMPLX seems to perform some casts: https://en.cppreference.com/w/c/numeric/complex/CMPLX I am not sure if the raw form 1 + 2*I does these under the hood.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2021-01-20 13:40 -0800 |
| Message-ID | <rua818$1c1u$2@gioia.aioe.org> |
| In reply to | #158510 |
On 1/20/2021 1:39 PM, Chris M. Thomasson wrote: > On 1/15/2021 10:27 PM, Beej wrote: >> Time for another esoteric question! >> >> ---------- >> >> #include <complex.h> >> >> double complex a = CMPLX(1, 2); >> double complex b = 1 + 2*I; >> >> ---------- >> >> They compare equal, of course. >> >> Are there any differences between the two values, i.e. whether or not >> CMPLX() is used? > [...] > > Well, CMPLX seems to perform some casts: > > https://en.cppreference.com/w/c/numeric/complex/CMPLX > > I am not sure if the raw form 1 + 2*I does these under the hood. > CMPLX might suppress some warnings.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2021-01-20 17:40 -0500 |
| Message-ID | <ruabhh$at2$1@dont-email.me> |
| In reply to | #158510 |
On 1/20/21 4:39 PM, Chris M. Thomasson wrote: > On 1/15/2021 10:27 PM, Beej wrote: >> Time for another esoteric question! >> >> ---------- >> >> #include <complex.h> >> >> double complex a = CMPLX(1, 2); >> double complex b = 1 + 2*I; >> >> ---------- >> >> They compare equal, of course. >> >> Are there any differences between the two values, i.e. whether or not >> CMPLX() is used? > [...] > > Well, CMPLX seems to perform some casts: > > https://en.cppreference.com/w/c/numeric/complex/CMPLX > > I am not sure if the raw form 1 + 2*I does these under the hood. CMPLX casts both of it's arguments to double. It's supposed to behave as though it uses _Imaginary_I, even on implementations that don't support _Imaginary types. That shouldn't matter for the particular values being used here. The multiplication results in a value of _Imaginary double type. The addition gives a result of _Complex double type. Those exact same conversions occur implicitly in 1 + 2*I, with one minor complication. I can expand to either _Imaginary_I or _Complex_I. If it is _Complex_I, then 2*I has _Complex double type rather than _Imaginary double, however, it has the same value regardless of which type it has. When 1 is added to it, 1 is converted to double, and the result is _Complex double. It shouldn't make any difference which of the two you use.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2021-01-20 14:57 -0800 |
| Message-ID | <ruachi$18da$1@gioia.aioe.org> |
| In reply to | #158514 |
On 1/20/2021 2:40 PM, James Kuyper wrote: > On 1/20/21 4:39 PM, Chris M. Thomasson wrote: >> On 1/15/2021 10:27 PM, Beej wrote: >>> Time for another esoteric question! >>> >>> ---------- >>> >>> #include <complex.h> >>> >>> double complex a = CMPLX(1, 2); >>> double complex b = 1 + 2*I; >>> >>> ---------- >>> >>> They compare equal, of course. >>> >>> Are there any differences between the two values, i.e. whether or not >>> CMPLX() is used? >> [...] >> >> Well, CMPLX seems to perform some casts: >> >> https://en.cppreference.com/w/c/numeric/complex/CMPLX >> >> I am not sure if the raw form 1 + 2*I does these under the hood. > > CMPLX casts both of it's arguments to double. It's supposed to behave as > though it uses _Imaginary_I, even on implementations that don't support > _Imaginary types. Did not know that. To create an I... well: double complex I = CMPLX(0, 1); should do. > That shouldn't matter for the particular values being > used here. The multiplication results in a value of _Imaginary double > type. The addition gives a result of _Complex double type. > > Those exact same conversions occur implicitly in 1 + 2*I, with one minor > complication. I can expand to either _Imaginary_I or _Complex_I. If it > is _Complex_I, then 2*I has _Complex double type rather than _Imaginary > double, however, it has the same value regardless of which type it has. > When 1 is added to it, 1 is converted to double, and the result is > _Complex double. > > It shouldn't make any difference which of the two you use. > Agreed.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2021-01-20 19:21 -0500 |
| Message-ID | <ruahe1$ghg$1@dont-email.me> |
| In reply to | #158515 |
On 1/20/21 5:57 PM, Chris M. Thomasson wrote: > On 1/20/2021 2:40 PM, James Kuyper wrote: ... >> CMPLX casts both of it's arguments to double. It's supposed to behave as >> though it uses _Imaginary_I, even on implementations that don't support >> _Imaginary types. > > Did not know that. To create an I... well: > > double complex I = CMPLX(0, 1); That's equivalent to _Complex_I, and _Complex_I is one of the two permissible permitted expansions for I.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2021-01-20 19:44 -0800 |
| Message-ID | <ruatal$pq5$1@gioia.aioe.org> |
| In reply to | #158516 |
On 1/20/2021 4:21 PM, James Kuyper wrote: > On 1/20/21 5:57 PM, Chris M. Thomasson wrote: >> On 1/20/2021 2:40 PM, James Kuyper wrote: > ... >>> CMPLX casts both of it's arguments to double. It's supposed to behave as >>> though it uses _Imaginary_I, even on implementations that don't support >>> _Imaginary types. >> >> Did not know that. To create an I... well: >> >> double complex I = CMPLX(0, 1); > > That's equivalent to _Complex_I, and _Complex_I is one of the two > permissible permitted expansions for I. > Thanks. I am not totally familiar with C99 complex. https://en.cppreference.com/w/c/numeric/complex/Complex_I The following quote is interesting to me: "Unlike _Imaginary_I and CMPLX, use of this macro to construct a complex number may lose the sign of zero on the imaginary component."
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-01-27 07:30 -0800 |
| Message-ID | <86o8hal7nn.fsf@linuxsc.com> |
| In reply to | #158393 |
beej@beej.us (Beej) writes:
> Time for another esoteric question!
>
> ----------
>
> #include <complex.h>
>
> double complex a = CMPLX(1, 2);
> double complex b = 1 + 2*I;
>
> ----------
>
> They compare equal, of course. [..discussion of possible
> differences..]
Normally I would prefer to avoid either form. If what you care
about is complex values in ordinary code (ie, in statements or
initializers for non-static locals), you can use something
like this:
typedef double _Complex Z;
typedef union { double xy[2]; Z z; } Union_xy_Z;
#define COMPLEX(x,y) ( (Union_xy_Z){ .xy[0]=(x), .xy[1]=(y) }.z )
Z
minus_one_example_a(){
Z i = COMPLEX( 0, 1 );
return i*i;
}
This COMPLEX macro does not need any header, and works in both
C99 and C11 (provided of course _Complex is supported). It does
have a drawback, in that it cannot be used in initializers at the
top level (what the C standard calls "external definitions").
However, we can define a macro that gives a value of a pointer to
a complex:
#define A_COMPLEX(x,y) ( (Z*) &COMPLEX( x, y ) )
static const Z *const pI = A_COMPLEX( 0, 1 );
Z
minus_one_example_b(){
return *pI * *pI;
}
Note that the variable 'pI' need not be declared 'const' (for
either or both of the two 'const' modifiers in the declaration).
The A_COMPLEX macro works for external definitions, but because
of how compound literals are defined A_COMPLEX does not work for
'static' declarations inside a function. So if we really need a
function-local static, an explicit intermediate object can be
used to do that:
Z
minus_one_example_c(){
static Union_xy_Z xy_I = {{ 0, 1 }};
Z *const pI = & xy_I.z;
return *pI * *pI;
}
The expression '*pI' can be used to update as well as read the
function-local static object xy_I.z.
All the above is required by the C standard to work in C.
Furthermore, because the two components of a complex are stored
directly, rather than being combined using multiplication or
addition, losing the sign of a (floating) negative zero shouldn't
ever happen.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web