Compilation platform that takes into account the FPU rounding mode when printing, conversions

EDIT: I made a mistake during the debugging session that made me ask this question. The differences I saw actually consisted in printing the double and parsing the double ( strtod ). Stephen’s answer still covers my question very well even after this correction, so I think I’ll leave this question alone if it is useful to anyone.

Some (most) C-compilation platforms that I have access to do not take FPU rounding mode into account when

  • converting a 64-bit integer to double ;
  • double print.

There is nothing exotic here: Mac OS X Leopard, various versions of Linux and BSD, Windows.

Mac OS X Snow Leopard, on the other hand, seems to take into account rounding when doing these two things. Of course, different behavior does not annoy me.

Here are typical snippets for two cases:

 #if defined(__OpenBSD__) || defined(__NetBSD__) # include <ieeefp.h> # define FE_UPWARD FP_RP # define fesetround(RM) fpsetround(RM) #else # include <fenv.h> #endif #include <float.h> #include <math.h> fesetround(FE_UPWARD); ... double f; long long b = 2000000001; b = b*b; f = b; ... printf("%f\n", 0.1); 

My questions:

  • Is there anything not ugly that I can do to normalize behavior on all platforms? Some hidden settings to tell platforms that take into account rounding mode, not vice versa or vice versa?
  • Is this the standard behavior?
  • What can I meet when FPU rounding mode is not used? Round to zero? Round to the nearest? Please tell me that there is only one alternative :)

Regarding 2. I found a place in the standard where it says that floats converted to integers always truncate (round to zero), but I could not find anything for integers → float.

+4
source share
1 answer

If you have not set the rounding mode, this should be the default mode of IEEE-754, which is rounded to the nearest.

For conversions from integer to float, the C standard says (§6.3.1.4):

When a value of an integer type is converted to a real floating type, if the value conversion can be accurately represented in the new type, it has not changed. If the converted value is in the range of values ​​that can be represented, but cannot be exactly, the result is either the nearest higher or the nearest lower representable value selected in the implementation-defined one. If the converted value is outside the range of values ​​that can be represented, the behavior is undefined.

Thus, both behaviors comply with standard C.

Standard C says (§F.5) that conversions between IEC60559 floating point formats and character sequences must be correctly rounded in accordance with IEEE-754. For formats other than IEC60559, recommended, but not required. The 1985 IEEE-754 standard states (section 5.4):

Conversions must be correctly rounded as indicated in section 4 for operands lying within the limits indicated in Table 3. Otherwise, for rounding to the nearest, the error in the converted result should not exceed 0.47 units in the least significant destination figure - the error that incurred rounding the specifications of section 4 provided that the exponent behind / underflow does not occur. In the modes of directional rounding, the error should have the correct sign and should not exceed 1.47 units in the last place.

Which section (4) states that the operation must be carried out in accordance with the prevailing rounding regime. That is, if you change the rounding mode, IEEE-754 says that the result of the conversion float-> string should change accordingly. Same for integers -> floating conversions.

The 2008 version of the IEEE-754 standard states (section 4.3):

The rounding attribute affects all computational operations; this may be inaccurate. Inaccurate numbers floating point results always have the same sign as the unlit result.

Both transforms are defined as computational operations in Section 5, so they must be performed in accordance with the prevailing rounding mode.

I would say that Snow Leopard has the correct behavior here (assuming that it rounds the results correctly according to the prevailing rounding mode). If you want to force the old behavior, you can always wrap your printf calls with code that changes the rounding mode, I suppose, although this is clearly not ideal.

Alternatively, you can use the %a format specifier (hexadecimal floating point) on platforms compatible with C99. Since the result of this conversion is always accurate, it will never be implemented in the prevailing rounding mode. I don't think the Windows C library supports %a , but you can probably be able to easily port the BSD or glibc implementation if you need it.

+4
source

Source: https://habr.com/ru/post/1306291/


All Articles