www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Union copy

reply =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
Consider the following on a 32-bit system:

     union Foo
     {
         struct
         {
             void* v;
             int i;
         }

         double d;
     }

     static assert(Foo.sizeof == 8);

     void copy(Foo* a, Foo* b)
     {
         version(one)
         {
             a.v = b.v;
             a.i = b.i;
         }
         version(two)
         {
             a.d = b.d;
         }
     }

Is there a difference between version one and version two? I was 
getting erroneous copies with version two on Linux and Windows, 
while it worked fine on OS X. Does it make a difference if the 
double is a NaN?
Oct 21 2013
next sibling parent =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
BTW, I know I can copy the structs directly using the assignment 
operator, but I was trying to avoid mixing (translating C -> D) 
with refactoring / improving.
Oct 21 2013
prev sibling next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Tuesday, 22 October 2013 at 02:47:39 UTC, Luís Marques wrote:
    static assert(Foo.sizeof == 8);
No idea how this is passing on your PC. Are you missing align directive in the snippet?
Oct 22 2013
parent "Dicebot" <public dicebot.lv> writes:
Ah, nvm, have not noticed the 32-bit part.
Oct 22 2013
prev sibling next sibling parent reply =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
Given the lack of feedback, I'm sending a sample scenario and 
results:

     union Foo
     {
         struct
         {
             void* v;
             int i;
         }

         double d;
     }

     static assert(Foo.sizeof == 8);

     void copy(Foo* a, Foo* b)
     {
         version(one)
         {
             a.v = b.v;
             a.i = b.i;
         }
         version(two)
         {
             a.d = b.d;
         }
     }

     void main()
     {
         Foo a;
         Foo b;
         b.i = 0x7ff7a502;
         copy(&a, &b);
         writef("%x\n", a.i);
         writeln(a.d);
     }

Linux (32-bits):

     $ dmd -version=one test.d && ./test
     7ff7a502
     nan

     $ dmd -version=two test.d && ./test
     7fffa502  <-- different
     nan

OS X (64-bits, binary forced to 32-bits):

     $ dmd -m32 -version=one test.d && ./test
     7ff7a502
     nan

     $ dmd -m32 -version=two test.d && ./test
     7ff7a502   <-- equal
     nan
Oct 23 2013
parent reply "Dicebot" <public dicebot.lv> writes:
Can you check the value of `double` field in the copy origin 
(immediately after initialization). It may have something to do 
with floating arithmetic.
Oct 23 2013
parent reply =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
On Wednesday, 23 October 2013 at 14:43:07 UTC, Dicebot wrote:
 Can you check the value of `double` field in the copy origin 
 (immediately after initialization). It may have something to do 
 with floating arithmetic.
// updated (b.v and writeln) void main() { Foo a; Foo b; b.v = null; b.i = 0x7ff7a502; writeln("b.d: ", b.d); copy(&a, &b); writef("a.i: %x\n", a.i); writeln("a.d: ", a.d); } Linux: $ dmd -version=one test.d && ./test b.d: nan a.i: 7ff7a502 a.d: nan $ dmd -version=two test.d && ./test b.d: nan a.i: 7fffa502 a.d: nan OS X: $ dmd -m32 -version=one test.d && ./test b.d: nan a.i: 7ff7a502 a.d: nan $ dmd -m32 -version=two test.d && ./test b.d: nan a.i: 7ff7a502 a.d: nan
Oct 23 2013
parent reply "Dicebot" <public dicebot.lv> writes:
I am afraid you will need to investigate IEEE spec on NaN 
assignment here to tell if this is a bug or valid behavior. I 
have made a quick check but it does not say anything about 
preserving NaN payload.
Oct 23 2013
next sibling parent =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
On Wednesday, 23 October 2013 at 15:21:20 UTC, Dicebot wrote:
 I am afraid you will need to investigate IEEE spec on NaN 
 assignment here to tell if this is a bug or valid behavior. I 
 have made a quick check but it does not say anything about 
 preserving NaN payload.
OK, thanks for the attempt anyway :-)
Oct 23 2013
prev sibling parent reply =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
On Wednesday, 23 October 2013 at 15:21:20 UTC, Dicebot wrote:
 I am afraid you will need to investigate IEEE spec on NaN 
 assignment here to tell if this is a bug or valid behavior. I 
 have made a quick check but it does not say anything about 
 preserving NaN payload.
I checked, it is not the payload of the NaN that is being changed.
Oct 23 2013
parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 23 October 2013 at 15:55:59 UTC, Luís Marques wrote:
 On Wednesday, 23 October 2013 at 15:21:20 UTC, Dicebot wrote:
 I am afraid you will need to investigate IEEE spec on NaN 
 assignment here to tell if this is a bug or valid behavior. I 
 have made a quick check but it does not say anything about 
 preserving NaN payload.
I checked, it is not the payload of the NaN that is being changed.
I have reproduces the case and it is payload for sure (did you took endianness into account?)
Oct 23 2013
parent reply =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
On Wednesday, 23 October 2013 at 16:27:56 UTC, Dicebot wrote:
 I have reproduces the case and it is payload for sure (did you 
 took endianness into account?)
Hmmm, how are you concluding that? My assertion that the NaN payload was being correctly preserved was based on the following: union Foo { double d; long l; } void main() { Foo src; Foo dst1; Foo dst2; src.l = 0x7ff7a50200000000; dst1.l = src.l; dst2.d = src.d; writef("src.l:\t%x\n", src.l); writef("dst1.l:\t%x\n", dst1.l); writef("dst2.l:\t%x\n", dst2.l); writef("dst1.payload:\t%x\n", getNaNPayload(dst1.d)); writef("dst2.payload:\t%x\n", getNaNPayload(dst2.d)); } Linux, 32-bit: $ dmd test.d && ./test src.l: 7ff7a50200000000 dst1.l: 7ff7a50200000000 <- the binary representation dst2.l: 7fffa50200000000 <- is different dst1.payload: 3d2810 <- but the decoded payloads dst2.payload: 3d2810 <- seem to be equal
Oct 23 2013
parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 23 October 2013 at 16:48:22 UTC, Luís Marques wrote:
 Hmmm, how are you concluding that?
By simply printing all bytes of a union as %b (binary) and checking bit pattern as per http://en.wikipedia.org/wiki/NaN :) I am not really proficient in IEEE stuff so checking bits is only thing I am capable of :P
Oct 23 2013
next sibling parent "Dicebot" <public dicebot.lv> writes:
P.S. getNaNPayload takes `real`, not `double` and any floating 
numbers conversions may be destructive.
Oct 23 2013
prev sibling parent reply =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
On Wednesday, 23 October 2013 at 16:58:21 UTC, Dicebot wrote:
 By simply printing all bytes of a union as %b (binary) and 
 checking bit pattern as per http://en.wikipedia.org/wiki/NaN :) 
 I am not really proficient in IEEE stuff so checking bits is 
 only thing I am capable of :P
I'm not sure I follow. The values I have are: src.l: 7ff7a50200000000 dst1.l: 7ff7a50200000000 (0111111111110111101001010000001000000000000000000000000000000000) dst2.l: 7fffa50200000000 (0111111111111111101001010000001000000000000000000000000000000000) dst1.d: nan dst2.d: nan dst1.payload: 3d2810 dst2.payload: 3d2810 Making the bit pattern more explicit: S E F P 0 11111111111 0 111101001010000001000000000000000000000000000000000 0 11111111111 1 111101001010000001000000000000000000000000000000000 Is the only different bit not the quiet/signaling NaN flag? Why do you say that the payload is different?
Oct 23 2013
parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 23 October 2013 at 17:47:54 UTC, Luís Marques wrote:
 Is the only different bit not the quiet/signaling NaN flag? Why 
 do you say that the payload is different?
Because I am terrible at arithmetic, nevermind :) If it is exactly q/s flag, IEEE spec yummies are even more likely. Not like bit copying via floating assignment is a good idea anyway.
Oct 23 2013
parent =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
On Wednesday, 23 October 2013 at 21:22:30 UTC, Dicebot wrote:
 Because I am terrible at arithmetic, nevermind :) If it is 
 exactly q/s flag, IEEE spec yummies are even more likely. Not 
 like bit copying via floating assignment is a good idea anyway.
Well, thanks for trying to help :-)
Oct 23 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 10/21/2013 07:47 PM, "Luís Marques" <luis luismarques.eu>" wrote:

 Consider the following on a 32-bit system:

      union Foo
      {
          struct
          {
              void* v;
              int i;
          }

          double d;
      }

      static assert(Foo.sizeof == 8);

      void copy(Foo* a, Foo* b)
      {
          version(one)
          {
              a.v = b.v;
              a.i = b.i;
          }
          version(two)
          {
              a.d = b.d;
          }
      }

 Is there a difference between version one and version two? I was getting
 erroneous copies with version two on Linux and Windows, while it worked
 fine on OS X. Does it make a difference if the double is a NaN?
If D's unions are like C's and C++'s, then it is not defined what happens when accessing members of the union that are not active. Either the anonymous struct or 'd' above is active, so only that member can be accessed. Ali
Oct 23 2013
parent reply =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
On Wednesday, 23 October 2013 at 18:07:37 UTC, Ali Çehreli wrote:
 If D's unions are like C's and C++'s, then it is not defined 
 what happens when accessing members of the union that are not 
 active.

 Either the anonymous struct or 'd' above is active, so only 
 that member can be accessed.
Is it not valid to initialize a double with a bit pattern that you read from somewhere (e.g. disk)? (reinterpret cast, I guess?). Something like this(?): void main() { long srcL = 0x7ff7a50200000000; double* srcD = cast(double*) &srcL; double dst = *srcD; writef("src: %x\n", srcL); writef("dst: %x\n", *cast(long*) cast(void*) &dst); } If this is valid, the question seems to be why the quiet/signaling flag is changed.
Oct 23 2013
parent =?UTF-8?B?Ikx1w61z?= Marques" <luis luismarques.eu> writes:
On Wednesday, 23 October 2013 at 18:19:14 UTC, Luís Marques wrote:
     void main()
     {
         long srcL = 0x7ff7a50200000000;
         double* srcD = cast(double*) &srcL;
         double dst = *srcD;

         writef("src: %x\n", srcL);
         writef("dst: %x\n", *cast(long*) cast(void*) &dst);
     }

 If this is valid, the question seems to be why the 
 quiet/signaling flag is changed.
(changed during the dst = *srcD assignment, I suppose): src: 7ff7a50200000000 dst: 7fffa50200000000
Oct 23 2013