11

Questions like "Why isn't 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 = 0.8?" got me thinking that...

... It would probably be nice to have the compiler warn about the floating-point constants that it rounds to the nearest representable in the binary floating-point type (e.g. 0.1 and 0.8 are rounded in radix-2 floating-point, otherwise they'd need an infinite amount of space to store the infinite number of digits).

I've looked up gcc warnings and so far found none for this purpose (-Wall, -Wextra, -Wfloat-equal, -Wconversion, -Wcoercion (unsupported or C only?), -Wtraditional (C only) don't appear to be doing what I want).

I haven't found such a warning in Microsoft Visual C++ compiler either.

Am I missing a hidden or rarely-used option?

Is there any compiler at all that has this kind of warning?

EDIT: This warning could be useful for educational purposes and serve as a reminder to those new to floating-point.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
  • No, because the compiler would go just nuts over virtually any serious numeric code. Most base-10 floating point numbers can't be represented exactly (and that includes really common things like π) – nneonneo Sep 27 '12 at 10:40
  • @nneonneo gcc appears to be converting exactly convertible constants just fine and everything according to IEE-754 (AFAIR, MSVC has double-rounding bugs), so it doesn't seem like it's something impossible (I've implemented a check for exact convertibility once). And I'm not requiring this option to be turned on at all times. – Alexey Frunze Sep 27 '12 at 10:43
  • Just imagine, how compiler will handle the situation `f1 + f2 + f3` i.e. using variable instead of number literal. Such practice is more practical and thus the warning will seldom triggered in usual code. – iammilind Sep 27 '12 at 10:45
  • Oh, I know there are exactly-convertible constants. But, on the grand scale of things, such things are exceedingly rare. If someone generates a bunch of filter constants with `MATLAB` and puts it in C code, you can bet all of those constants will not be "exactly convertible". Pretty well all of the magic numbers in `libm` (excluding 0, 0.5 and 1) aren't exactly convertible. – nneonneo Sep 27 '12 at 10:46
  • @iammilind I'm asking about individual constants, not about constant (or non-constant) expressions containing multiple floating-point constants. – Alexey Frunze Sep 27 '12 at 10:48
  • On the grand scale of things: if you don't know which numbers are guaranteed to be represented exactly, then you probably shouldn't be using machine floating point. Even if the input can be converted exactly, there are too many other things to consider. – James Kanze Sep 27 '12 at 10:53
  • @nneonneo The fact that π can't be represented exactly isn't really an issue here, since you can't represent it exactly in base 10 either, so you can't use it as a floating point literal. Things like `1.1` or `3.14159` _are_ issues, however. – James Kanze Sep 27 '12 at 10:55
  • 1
    @James: or to be more specific, if you need to know, then don't use float. If you don't know and also don't care, you're fine :-) – Steve Jessop Sep 27 '12 at 10:55
  • I tried to search for this option, but the search just led right back here.. – harold Sep 27 '12 at 11:31
  • 1
    You might like this blog post about a recently added warning to a C static analyzer: http://blog.frama-c.com/index.php?post/2011/11/19/Just-a-few-more-digits-please – Pascal Cuoq Sep 27 '12 at 12:44
  • 2
    @nneonneo: libm sources (or, at least, good math library sources) do not contain “magic numbers”. They contain numbers that have been carefully crafted by experts and that obey technological and engineering rules, not magic. When the numbers are designed, they could be easily represented with exact numerals (such as hexadecimal floating-point); math library sources are a place where exact values ought to be used and this warning would be useful, not a place where slop should be disregarded and accepted as normal. – Eric Postpischil Sep 27 '12 at 13:27
  • Just use -Wfloat-equal. This warns about often error-prone checks for equality between floats. In most cases (especially education), a check for equality of floats is false and a trust region is advised. (For the purpose of "did the value change from initialization" it's still fine). A warning about every inexact floating point representation of a number would be insane. – stefan Sep 27 '12 at 13:45
  • 1
    @stefan That warning doesn't warn about the constants themselves, which is what I want. – Alexey Frunze Sep 27 '12 at 13:48
  • @AlexeyFrunze Yes, I know. But in my opinion, such a warning would be even bad for education. A beginner would be doubtful about the correctness of the code and would be hesitating to continue. Or he ignores the warning which reduces it to noise only. You can't do it any better, so the warning doesn't give you a hint to a possible improvement. Warning about error-prone equality comparisons is useful, since you can avoid that. Noone should ever worry about inexact representation of decimals. It's a waste of time (at least with our kind of computers) – stefan Sep 27 '12 at 14:01
  • @EricPostpischil: I think @nneonneo was trying to get at the "magic numbers" in `math.h` prescribed by POSIX: things like `M_PI` and `M_SQRT2`. – Stephen Canon Sep 27 '12 at 15:16
  • @stefan: The beginner **should** be doubtful about the correctness of the code. That is the point: Teach people to understand floating-point and use it correctly. Discourage the sloppy programming that is common today. Worrying about inexact representation of decimals is not a waste of time in certain fields of software. – Eric Postpischil Sep 27 '12 at 15:27
  • @EricPostpischil I agree on beginners beeing doubtful. However if there is no alternative (i.e. there is no way of "correcting" the constants), it adds a feeling of non-confidence. Beginners are confused by warnings. There is too much information so filtering the important stuff is difficult. If they can't change it, it's a useless warning. Despite of the very limited field in which this stuff is important, beginners should worry about float operations, not float constants. Hence, enable -Wfloat-equal, but not that kind of "This is the way computers work, you can't change this" warning. – stefan Sep 27 '12 at 16:05

4 Answers4

8

There is no technical reason the compiler could not issue such warnings. However, they would be useful only for students (who ought to be taught how floating-point arithmetic works before they start doing any serious work with it) and people who do very fine work with floating-point. Unfortunately, most floating-point work is rough; people throw numbers at the computer without much regard for how the computer works, and they accept whatever results they get.

The warning would have to be off by default to support the bulk of existing floating-point code. Were it available, I would turn it on for my code in the Mac OS X math library. Certainly there are points in the library where we depend on every bit of the floating-point value, such as places where we use extended-precision arithmetic, and values are represented across more than one floating-point object (e.g., we would have one object with the high bits of 1/π, another object with 1/π minus the first object, and a third object with 1/π minus the first two objects, giving us about 150 bits of 1/π). Some such values are represented in hexadecimal floating-point in the source text, to avoid any issues with compiler conversion of decimal numerals, and we could readily convert any remaining numerals to avoid the new compiler warning.

However, I doubt we could convince the compiler developers that enough people would use this warning or that it would catch enough bugs to make it worth their time. Consider the case of libm. Suppose we generally wrote exact numerals for all constants but, on one occasion, wrote some other numeral. Would this warning catch a bug? Well, what bug is there? Most likely, the numeral is converted to exactly the value we wanted anyway. When writing code with this warning turned on, we are likely thinking about how the floating-point calculations will be performed, and the value we have written is one that is suitable for our purpose. E.g., it may be a coefficient of some minimax polynomial we calculated, and the coefficient is as good as it is going to get, whether represented approximately in decimal or converted to some exactly-representable hexadecimal floating-point numeral.

So, this warning will rarely catch bugs. Perhaps it would catch an occasion where we mistyped a numeral, accidentally inserting an extra digit into a hexadecimal floating-point numeral, causing it to extend beyond the representable significand. But that is rare. In most cases, the numerals we use are either simple and short or are copied and pasted from software that has calculated them. On some occasions, we will hand-type special values, such as 0x1.fffffffffffffp0. A warning when an extra “f” slips into that numeral might catch a bug during compilation, but that error would almost certainly be caught quickly in testing, since it drastically alters the special value.

So, such a compiler warning has little utility: Very few people will use it, and it will catch very few bugs for the people who do use it.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • OK, this seems to be the best I can get. – Alexey Frunze Sep 28 '12 at 21:57
  • What would you think of the idea of having suffixes to indicate whether a floating-point constant was expected to represent an exact quantity, was expected to represent a quantity which was accurate to the precision specified, or was expected to represent the closest representable value to a more precise value specified? Under the first criterion, 999999.125 would be an acceptable `float`, but 999999.1, 999999.12, and 999999.13 would not. Those latter three would be accepted under the second criterion, but 999999.10 or 999999.14 would not. Would that seem helpful? – supercat Feb 10 '14 at 23:06
  • @supercat: Fine by me. It is the compiler and language developers you have to convince. – Eric Postpischil Feb 11 '14 at 00:07
1

The warning is in the source: when you write float, double, or long double including any of their respective literals. Obviously, some literals are exact but even this doesn't help much: the sum of two exact values may inexact, e.g., if the have rather different scales. Having the compiler warn about inexact floating point constants would generate a false sense of security. Also, what are you meant to do about rounded constants? Writing the exact closest value explicitly would be error prone and obfuscate the intent. Writing them differently, e.g., writing 1.0 / 10.0 instead of 0.1 also obfuscates the intent and could yield different values.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
1

There will be no such compiler switch and the reason is obvious. We are writing down the binary components in decimal:

First fractional bit is 0.5

Second fractional bit is 0.25

Third fractional bit is 0.125

....

Do you see it ? Due to the odd endings with the number 5 every bit needs another decimal to represent it exactly. One bit needs one decimal, two bits needs two decimals and so on.

So for fractional floating points it would mean that for most decimal numbers you need 24(!) decimal digits for single precision floats and 53(!!) decimal digits for double precision. Worse, the exact digits carry no extra information, they are pure artifacts caused by the base change.

Noone is going to write down 3.141592653589793115997963468544185161590576171875 for pi to avoid a compiler warning.

Thorsten S.
  • 4,144
  • 27
  • 41
  • I know very well how this stuff works. What's your answer anyway? The closest so far is Pascal Cuoq's comment. Btw, the compiler could include the rounded value (like that pi) in the warning. – Alexey Frunze Sep 27 '12 at 13:32
  • Clear cut question: Do you want to write down every fractional numeral with the required amount of decimal digits (e.g. Pascals 0.1000000000000000055511151231257827021181583404541015625) ? – Thorsten S. Sep 27 '12 at 13:45
  • I already said that there will be no such compiler switch in standard compilers. Eric Postpischil explains this in detail if you are not satisfied with my answer. And I explained the reason for that. – Thorsten S. Sep 27 '12 at 13:50
-1

I don't see how a compiler would know or that the compiler can warn you about something like that. It is only a coincidence that a number can be exactly represented by something that is inherently inaccurate.

graham.reeds
  • 16,230
  • 17
  • 74
  • 137
  • 1
    *technically* it can, since it knows the declaration you used to get the floating point value (and certain floats, like small integers and multiples-of-powers-of-2, can be represented exactly). – nneonneo Sep 27 '12 at 10:42
  • 1
    [This code](http://stackoverflow.com/a/8455604/968261) did the conversion and the check pretty well. A compiler could certainly do it. – Alexey Frunze Sep 27 '12 at 10:46
  • 3
    It would be easy for the compiler to warn, since it knows the floating point format, and it knows the exact value it converts the literal to. And it's not a "coincidence" whether a decimal number has an exact representation in machine floating point; it's totally deterministic. (In particular, there's a very large range of integers which have exact representations.) And finally, every machine floating point value represents an exact number. (Not necessarily the number you want, of course, but that doesn't mean that it's inexact.) – James Kanze Sep 27 '12 at 10:50
  • Maybe my use of the word coincidence was incorrect but the feeling behind it remains the same. Also if you are worried about whether a number can be represented exactly then you probably shouldn't be using floating point. – graham.reeds Sep 27 '12 at 11:00