0

I am facing the below which is when I run below code

int main() 
{
  float test = -6.25f;    
  
  unsigned int result_1;
   
  result_1= (unsigned int)test ;
  printf("test result_1: %x \n", result_1);
  
  return 0;
}

The output on arm is equal 0 and output on intel is equal 4294967291 .

Do you know how can force intel compiler to make output 0 as arm compiler?

mch
  • 9,424
  • 2
  • 28
  • 42
mohamed
  • 9
  • 3

2 Answers2

4

From https://en.cppreference.com/w/c/language/conversion :

Real floating-integer conversions

A finite value of any real floating type can be implicitly converted to any integer type. Except where covered by boolean conversion above, the rules are:

  • The fractional part is discarded (truncated towards zero).

    • If the resulting value can be represented by the target type, that value is used
    • otherwise, the behavior is undefined

Your code does:

float test = -6.25f;
(unsigned int)test;

The type unsigned int is not able to represent the value -6. You can't convert a float with a negative value to unsigned type. Your code has undefined behavior.

Do you know how can force intel compiler to make output 0 as arm compiler?

Check if the value is less than 0.

int result_1 = test < 0 ? 0 : <something else here>;

If your compiler if following ANNEX F addition to the C language, then according to https://port70.net/~nsz/c/c11/n1570.html#F.4

[...] if the integral part of the floating value exceeds the range of the integer type, then the ''invalid'' floating- point exception is raised and the resulting value is unspecified [...]

In which case anyway, the resulting value is unspecified, so it may differ between compilers as you experience.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • regarding this The type unsigned int is not able to represent the value -6. You can't convert a float with a negative value to unsigned type. in Arm, it gives 0 instead of 4294967290 and that actually I need to do it in intel compiler by casting not by if conditional statment if it is possible. – mohamed Feb 16 '22 at 11:34
  • 1
    @mohamed Why do you want to avoid the condition? – hyde Feb 16 '22 at 11:41
  • @mohamed I mean, it seems you want exactly `if (test < 0) result_1 = 0; else result_1 = test;`. There is that `if` there, and it'll be hard to get rid of. At best you can hide it, such as `result_1 = (unsigned int)max(0.0f, test);`, where `max` function/macro hides the test. – hyde Feb 16 '22 at 11:44
  • because, it is not only one casting need to be changed, they are many casting need to be changed, so I need to make it general and use the casting for all negative float values which need to be changed. – mohamed Feb 16 '22 at 11:46
  • 1
    `in Arm, it gives` In C language it is undefined behavior. The value `0` may be some leftover uninitialized value that just happens to be there and may change unexpectedly, or _this specific compiler decided_ to handle the case in _this specific way_. This would be a compiler extension. Consult your compiler documentation. If not documented, one would expect.to be undefined. See the linked question about undefined behavior - it exactly explains the case "hey, it works for me" vs "hey, for me the behavior differs" like you have with two different compilers. – KamilCuk Feb 16 '22 at 11:59
  • Btw. https://embeddeduse.com/2013/08/25/casting-a-negative-float-to-an-unsigned-int/ has _exactly_ the issue youare describing. – KamilCuk Feb 16 '22 at 12:09
  • 1
    @mohamed: Re “it is not only one casting need to be changed, they are many casting need to be changed”: If you do not want a solution that changes the source code, what kind of solution do you envision? There no processor mode that changes how its conversion instruction (`cvttss2si`) behaves in this regard. A switch that tells the compiler to generate different code? I doubt there is such a switch. Most likely, you will have to change the code. – Eric Postpischil Feb 16 '22 at 13:00
0

When converting an float to unsigned, code is subject to:

When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.) C17dr § 6.3.1.4 1

To avoid undefined behavior (UB) for that conversion for out-of-range values, code needs to test the float value first. The typical valid range for conversion is -0.999... to 4,294,967,295.999...

#define UINT_MAX_PLUS1_FLT ((UINT_MAX/2 + 1)*2.0f)

unsigned float_to_unsigned(float f) {
  // Exclude values that are too small, too big or NAN
  if (f > -1.0f && f < UINT_MAX_PLUS1_FLT) {
    return (unsigned) f;
  }
  return 0; // Adjust as desired
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256