1

I have simple code. On x86(visual studio) res is same for last two code lines.

short res;
double CONST = 32768.0
double d=-0.85;
res = ( unsigned short)( d * CONST );
res = ( short)( d * CONST );

On ARM(GCC) converting to unsigned get incorrect result.

short dres;
double CONST = 32768.0
double d=-0.85;
dres = ( unsigned short )( d * CONST );
//007db5c4:   vldr d17, [pc, #76]
//007db5c8:   vldr d16, [r11, #-20]
//007db5cc:   vmul.f64 d7, d17, d16 ;d7=={u8 = {51, 51, 51, 51, 51, 51, 219, 192}, u16 = {13107, 13107, 13107, 49371}, u32 = {858993459, 3235590963}, u64 = 13896757370177139507, f32 = {4.17232506e-08, -6.8499999}, f64 = -27852.799999999999}
//007db5d0:   vcvt.u32.f64 s15, d7 ;s15==0 !!!!!!!!!!!!!!!!!!!!! incorrect
//007db5d4:   vstr s15, [r11, #-48]
//007db5d8:   ldrh r3, [r11, #-48]
//007db5dc:   uxth r3, r3
//007db5e0:   strh r3, [r11, #-6]
dres = ( short )( d * CONST );
//007db5e4:   vldr d17, [pc, #44]
//007db5e8:   vldr d16, [r11, #-20]
//007db5ec:   vmul.f64 d16, d17, d16
//007db5f0:   vcvt.s32.f64 s15, d16 ;s15==-nan(0x7f9334)
//007db5f4:   vmov r3, s15
//007db5f8:   strh r3, [r11, #-6]

Is this correct behavior or bug?

Artem Romanov
  • 166
  • 1
  • 14
  • Are you comlaining that the hardware instruction `vcvt.u32.f64` does not correctly convert a negative double to an unsigned 32bit integer? Negative numbers can not be expressed with unsigned. Simple case of garbage in, garbage out. The C standard says it's undefined behavior (see duplicates answer) so gcc is correct in using the opcode that only works for positive numbers. – Goswin von Brederlow Jun 19 '18 at 13:11

1 Answers1

2

This is not a compiler bug.

For a 16 bit short, the behaviour of

res = ( unsigned short)( d * CONST );

is undefined due to your overflowing a signed type and the conversion of a float with a value of -1 or less to an unsigned integral type. This puts the entire program into an undefined state.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • Just a head's up for future reference since you've got a dupe hammer: From the SO [C wiki](https://stackoverflow.com/tags/c/info) FAQ, we have a canonical dupe under FAQ -> floating point arithmetic. – Lundin Jun 19 '18 at 11:59
  • It seems atypical behaviour for GCC though. From what I've seen previously, it usually just keeps the same bit pattern when converting an out-of-range unsigned value to a 2's complement format signed value. – Ian Abbott Jun 19 '18 at 12:02
  • And re my comment above, the online docs for GCC even say as much! https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html – Ian Abbott Jun 19 '18 at 12:13
  • @IanAbbott: There are two facets to the UB: I've added the other one (which admittedly is less well-known). – Bathsheba Jun 19 '18 at 12:15
  • Oh, so in this case, it is GCC's conversion of negative floating point values to unsigned integer values that is the issue, in that its undefined behaviour is to convert the value to 0. – Ian Abbott Jun 19 '18 at 12:21
  • @IanAbbott: That's the first bit of undefined-ness to be hit conceptually at least, although we are bordering on the illogical in unpicking undefined behaviour. – Bathsheba Jun 19 '18 at 12:23
  • Hmm yes, the first part (conversion from floating-point <= -1 to unsigned integer) is undefined, but the second part (conversion of integer value to signed integer that cannot represent the value) is either implementation-defined or causes an implementation-defined signal to be raised (6.3.1.3 para 3). – Ian Abbott Jun 19 '18 at 12:27