6

We have two embedded projects: One of them is using the cosmic compiler and the other one is using GCC. Both abide by ISO/IEC 9899:1990.

When we initialize a float with the literal 14.8f, it gets translated to the binary representation of 0x416CCCCC on the cosmic compiler and 0x416CCCCD by GCC.

The IEC standard at chapter 6.3.1.4, item 2, Floating types states:

If the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is either the nearest higher or nearest lower value, chosen in an implementation-defined manner.

as we are using these numbers as threshold, this obviously makes a difference.

The cosmic compiler states that it uses a round down implementation.
As GCC is quite more complex I was wondering if it has a compiler flag that allows choosing of the behavior at compile time. So far I have only found that you can choose FE_DOWNWARD, but that is related to run-time rather than compile-time.

Does anyone have a clue of such a flag for compile-time conversion?

Jan
  • 2,025
  • 17
  • 27
user1464603
  • 437
  • 4
  • 8
  • I doubt GCC has such a flag. However, you can use hexadecimal floating-point syntax to specify numbers in a way the compiler should convert correctly. In hexadecimal floating-point, the `float` just below 14.8 is `0x1.d99998p+3`. – Eric Postpischil Feb 23 '18 at 13:29
  • This question is somewhat related: https://stackoverflow.com/questions/46810474/comparing-floating-point-values-converted-from-strings-with-literals – Jabberwocky Feb 23 '18 at 13:33
  • "as we are using these numbers as threshold, this obviously makes a difference" Not very obvious. You have to compare float numbers with a +/- delta. If you use exact comparisons, the code might fail and problem is in your own code. – Lundin Feb 23 '18 at 13:35
  • Anyway, I suspect what you are looking for is fenv.h, a C99 header which introduced support to set/get the rounding direction in a portable manner. gcc likely had something similar pre-C99. The easiest would of course be to simply upgrade to C99, since it's the year 2018. – Lundin Feb 23 '18 at 13:42
  • 4
    @Lundin: Re “You have to compare float numbers with a +/- delta.” That is **false**. There is **no requirement** that floating-point numbers be compared that way. It is rubbish that spreads like rumor because it serves (poorly) in simplistic situations like student projects. Quite often, comparing with a tolerance is not a good solution; it is frequently recommended on Stack Overflow without any consideration for the false positives that it creates or consideration of what the tolerance should be. Often, somebody trying to compare for equality is misusing floating-point, so… – Eric Postpischil Feb 23 '18 at 13:43
  • 1
    … the correct recommendation is to redesign their solution, not to compare with a tolerance. But this person is comparing for less-than or less-than-or-equal-to, not equal-to. That is a different situation. Comparing to a threshold suggests they need to clamp values to bounds acceptable for some device or application. In such a case, comparing may be a suitable solution, with no tolerance. – Eric Postpischil Feb 23 '18 at 13:43
  • @EricPostpischil It entirely depends on your portability requirements. Anyway, this is apparently not what the OP is asking about, so we can drop that discussion. – Lundin Feb 23 '18 at 13:50
  • 1
    @Lundin: No, it does not depend entirely on your portability requirements. Comparing with a tolerance does not make a program portable. It likely makes a program wrong. Whether or not to compare with a tolerance depends on your application. If false positives are not acceptable for your application, then comparing with a tolerance will not work, regardless of the C implementation. – Eric Postpischil Feb 23 '18 at 14:00
  • user1464603, "cosmic compiler states that it uses a round down implementation" this is interesting. Are you sure it isn't round-toward -zero instead? – chux - Reinstate Monica Feb 23 '18 at 14:58

2 Answers2

4

Just for reference's sake, the relevant chapter in GCC's manual states:

How the nearest representable value or the larger or smaller representable value immediately adjacent to the nearest representable value is chosen for certain floating constants (C90 6.1.3.1, C99 and C11 6.4.4.2).

C99 Annex F is followed.

And in my draft C99 standard, Annex F says:

F.7.2 Translation

During translation the IEC 60559 default modes are in effect:

— The rounding direction mode is rounding to nearest.
— The rounding precision mode (if supported) is set so that results are not shortened.
— Trapping or stopping (if supported) is disabled on all floating-point exceptions

So that seem to clearly state that

  • GCC uses rounding to nearest.
  • You can't change it.

Using the hexadecimal syntax to get the exact desired float seems like the proper solution here, and (I guess) the reason that syntax exists.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • In C99 you can probably change it, with `fesetround`. – Lundin Feb 23 '18 at 13:44
  • Thanks for the clarification, as we have to be C90 compliant I guess there is no solution as the hex notation is C99 only. – user1464603 Feb 23 '18 at 13:44
  • @Lundin that only affects floating point calculations, not compile-time translation of literals. – user1464603 Feb 23 '18 at 13:45
  • @user1464603 Ah yeah I thought that was what you are after. It does indeed only affect the behavior of `round()`. – Lundin Feb 23 '18 at 13:46
  • @user1464603 You can of course write it yourself, but it's not going to be pretty (i.e. convert from `0x416CCCCC` at run-time). – unwind Feb 23 '18 at 13:50
  • @Lundin: It does not only affect the behavior of `round()`. It affects the behavior of floating-point operations generally, at run-time. – Eric Postpischil Feb 23 '18 at 13:52
1

If one wants to write the code in a manner that will yield matching behavior on C89 compilers, writing floating-point constants as a precisely-representable whole number divided by a power of two e.g. (15518925.0f/1048576.0f) should yield unambiguous results on all common floating-point implementations, regardless of rounding modes. There isn't generally any way to control how compile-time-constant expressions are rounded, but if one writes such expressions using the above form one can render such questions moot.

supercat
  • 77,689
  • 9
  • 166
  • 211