mishra@banach.ACA.MCC.COM (Aditya Mishra) (10/20/90)
BUG !!! BUG !!! BUG !!!
THIS PROGRAM DEMONSTRATES WHAT I BELIEVE IS A BUG IN FLOATING POINT
MULTIPLICATION IN 'C' !!
I ACCIDENTALLY STUMBLED ON A PATTERN OF
FLOATING POINT OPERAND VALUES FOR WHICH RESULTS ARE QUITE INACCURATE !!!
I WAS GETTING UNDESIRED BEHAVIOR IN A PROGRAM BECAUSE OF THIS (APPARENT) BUG.
I FELT IT MIGHT BE SERIOUS AND IMPORTANT TO ALL C USERS.
bug.c
-----
Aditya Mishra, MCC Austin (512) 338 3481
-----------------------------------------
(1) In the program, if float f = ... 0.64, 0.32, 0.16, 0.08, 0.04, 0.02,
0.01, 0.005, 0.0025, ..., etc (see the pattern?), the value
of i1 was one less than what it should be.
This error was absent if the value of f was not
from the above pattern (if f = 0.65, e. g.).
(2) Also, if float g = 1.0025, 1.32 or 9.0025 and some more values,
the result in float r2
(r2 = factor * g) was wrong after 2 or 3 decimal places.
(3) These bugs persist on cc (C compiler) on about six machines
that I could get my hands on.
(4) I am not sure if this is really a bug. I am just expressing an
experience that teaches me to be careful with floating point
results of multiplication.
*/
/*-- -- -- -- -- -- --*/
#include <stdio.h>
main()
{
int i1, i2;
float r1, r2;
float g = 9.0025;
float f = 0.32;
float factor = 10000.0;
i1 = factor * f; /* *even if* i = (int) (factor * f); */
r1 = factor * f;
i2 = factor * g; /* *even if* i = (int) (factor * g); */
r2 = factor * g;
printf("%d ", i1);
printf("%f \n", r1);
printf("%d ", i2);
printf("%f \n", r2);
}
/*-- -- -- -- -- -- --*/
kdq@demott.COM (Kevin D. Quitt) (10/20/90)
In article <1348@banach.ACA.MCC.COM> mishra@banach.ACA.MCC.COM (Aditya Mishra) writes: >BUG !!! BUG !!! BUG !!! > >THIS PROGRAM DEMONSTRATES WHAT I BELIEVE IS A BUG IN FLOATING POINT >MULTIPLICATION IN 'C' !! Calm down, take a deep breath. There. Feel better? This has nothing to do with C. It has to do with your individual compiler (which, by the way you didn't identify) on your particular machine (which you also didn't identify), the libraries used, and quite possibly the floating-point notation itself. cc on this machine also gets 3199 instead of 3200, but gnu's gcc gets this one right. They both miss the second one by one, so it's possible that this is due to the inherent inaccuracy of floating point numbers. If your need to be exactly on, use integers, not floating point, or round the data in the process of conversion to integer - remember: conversion from floating point to integer in C is defined as truncation, not rounding. If the floating point value is off by one LSB (as it's allowed to be in the IEEE spec), you will not get the correct integer. Please note the following warning generated by the Microsoft C compiler: foo.c(13) : warning C4051: type conversion - possible loss of data See what it's trying to tell you? So again, relaxen und vatchen das blinkenlites. -- _ Kevin D. Quitt demott!kdq kdq@demott.com DeMott Electronics Co. 14707 Keswick St. Van Nuys, CA 91405-1266 VOICE (818) 988-4975 FAX (818) 997-1190 MODEM (818) 997-4496 PEP last 96.37% of all statistics are made up.
henry@zoo.toronto.edu (Henry Spencer) (10/21/90)
In article <1348@banach.ACA.MCC.COM> mishra@banach.ACA.MCC.COM (Aditya Mishra) writes: >THIS PROGRAM DEMONSTRATES WHAT I BELIEVE IS A BUG IN FLOATING POINT >MULTIPLICATION IN 'C' !! There is no bug. You have discovered the joys of floating-point arithmetic. >(1) In the program, if float f = ... 0.64, 0.32, 0.16, 0.08, 0.04, 0.02, > 0.01, 0.005, 0.0025, ..., etc (see the pattern?), the value > of i1 was one less than what it should be. Note that float->int conversion truncates, while %f conversion rounds. You have come across boundary cases where this makes a difference, I'd say. Look hard and you will probably find more. >(2) Also, if float g = 1.0025, 1.32 or 9.0025 and some more values, > the result in float r2 > (r2 = factor * g) was wrong after 2 or 3 decimal places. Wrong after the decimal point, you mean? If so, no surprise: `float', as opposed to `double', often only has about seven digits of precision. In general, you should use `double' for all floating-point arithmetic you care about, unless speed or storage is critical and you have done a careful analysis of the tradeoffs involved. -- The type syntax for C is essentially | Henry Spencer at U of Toronto Zoology unparsable. --Rob Pike | henry@zoo.toronto.edu utzoo!henry
dan@kfw.COM (Dan Mick) (10/21/90)
In article <1348@banach.ACA.MCC.COM> mishra@banach.ACA.MCC.COM (Aditya Mishra) writes: >BUG !!! BUG !!! BUG !!! > >THIS PROGRAM DEMONSTRATES WHAT I BELIEVE IS A BUG IN FLOATING POINT >MULTIPLICATION IN 'C' !! Just out of curiosity: Why do you think this is a problem with C? Did it ever occur to you that it might be a problem with floating point on the machine? Did you try it in Pascal, or assembly, or FORTRAN, or as a thought experiment? True, the problems with floating-point math on computers *do* take some time and experience to find, if you've only done string and integer programs before, but have you never tried to add 0.99 and 0.01 on any machine, in any language, before? It's not C's fault. And, by the way: Do you know why it's against the law to yell "FIRE!" in a crowded theater?
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (10/22/90)
In article <1348@banach.ACA.MCC.COM>, mishra@banach.ACA.MCC.COM (Aditya Mishra) writes: > BUG !!! BUG !!! BUG !!! > THIS PROGRAM DEMONSTRATES WHAT I BELIEVE IS A BUG IN FLOATING POINT > MULTIPLICATION IN 'C' !! Please take the trouble to learn something about floating point arithmetic before screaming to the world that the sky is falling. > (1) In the program, if float f = ... 0.64, 0.32, 0.16, 0.08, 0.04, 0.02, > 0.01, 0.005, 0.0025, ..., etc (see the pattern?), the value > of i1 was one less than what it should be. [where i1 is calculated as float f = /* as above */; float factor = 10000.0; int i1 = factor * f; ] The problem here is that a number like 0.64 *CANNOT* *POSSIBLY* be represented exactly in (finite-precision) floating-point. At all. In *any* programming language. Any compiler, any string->fp converter, is going to have to round nearly every number there is (only numbers which are an integer times a power of 2 are likely to be exact); some of them will round up and some of them will round down. If it rounds down, i1 will be 1 less than you expected. If it rounds up, because floating pointer->integer conversion truncates towards zero, the error will be zapped away by the conversion. 2nd year CS students here know about this... One of the things I really like about C is that unlike Fortran and Pascal, it doesn't lie to the user. It doesn't make a false claim to support "real" arithmetic. It honestly and openly admits to 'float'. Believe it: what you get is floating-point, not real. -- Fear most of all to be in error. -- Kierkegaard, quoting Socrates.
jfc@athena.mit.edu (John F Carr) (10/22/90)
In article <1990Oct20.231726.3249@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >In general, you should use `double' for all floating-point arithmetic >you care about, unless speed or storage is critical and you have done >a careful analysis of the tradeoffs involved. On some newer machines, double is faster. 2 examples: the 68881 (used with the 680x0 and the IBM RT), and the IBM RS 6000. This is because the hardware does only high precision calculations, and must take extra cycles to round to single precision if that is what you ask for by using type float instead of double. -- John Carr (jfc@athena.mit.edu)
richard@iesd.auc.dk (Richard Flamsholt S0rensen) (10/22/90)
In article <4032@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: > The problem here is that a number like 0.64 *CANNOT* *POSSIBLY* be > represented exactly in (finite-precision) floating-point. At all. > In *any* programming language. [...] At least when using *binary* logic as your hardware ;-) -- /Richard Flamsholt richard@iesd.auc.dk
johnb@srchtec.UUCP (John Baldwin) (10/23/90)
>And, by the way: Do you know why it's against the law to yell "FIRE!" in >a crowded theater? I dunno; is it the same reason they have statutes against yelling "MOVIE!" in a crowded fire-house? [sorry, i couldn't resist! ;-} ] -- John T. Baldwin | "Pereant qui ante nos nostra dixerunt!" Search Technology, Inc. | (A plague on those who said our good johnb%srchtec.uucp@mathcs.emory.edu | things before we did!)
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (10/23/90)
In article <4032@goanna.cs.rmit.oz.au> I wrote: > The problem here is that a number like 0.64 *CANNOT* *POSSIBLY* be > represented exactly in (finite-precision) floating-point. At all. > In *any* programming language. [...] In article <RICHARD.90Oct22112830@lambda.iesd.auc.dk>, richard@iesd.auc.dk (Richard Flamsholt S0rensen) replied: > At least when using *binary* logic as your hardware ;-) I think he may have meant binary floating-point, and at that he may have meant "radix-2 floating-point", or in fact "floating- point with radix not a power of 10". I had some mail by people who hadn't paid any attention to the context. The context was that the original poster was upset because his program hadn't worked on six compiler/hardware combinations. In that context, _only_ the floating-point systems actually available to that poster are of relevance: a radix-10 floating-point system with 99 digits in the significand, whatever its merits, is of no interest because not available to that poster. I also note that 2 is distinctly better than other bases for floating- point arithmetic. I'm not just referring to the hidden bit (it's hard to "hide" more than one bit...), I'm referring to the law X (<) Y --> X (<=) {X (+) Y}(/)2 (<=) Y which bisection relies on. -- Fear most of all to be in error. -- Kierkegaard, quoting Socrates.
userAKDU@mts.ucs.UAlberta.CA (Al Dunbar) (10/23/90)
In article <1990Oct20.235102.15882@kfw.COM>, dan@kfw.COM (Dan Mick) writes: >In article <1348@banach.ACA.MCC.COM> mishra@banach.ACA.MCC.COM (Aditya Mishra) writes: >>BUG !!! BUG !!! BUG !!! >> >>THIS PROGRAM DEMONSTRATES WHAT I BELIEVE IS A BUG IN FLOATING POINT >>MULTIPLICATION IN 'C' !! > >Just out of curiosity: Why do you think this is a problem with C? > <<<stuff deleted>>> Hear, hear. Floating point precision seems to be a sticky topic these days. When people expect 4.4 and they get 4.3999987 they somehow think the answer is only good to one digit! The precision of the result of a floating point calculation doesn't relate to the number of digits of agreement, but to its numerical proximity to the correct answer. I always thought it misleading to consider (pardon, but my Fortran background is showing) REAL*4 (pardon, float) to be "accurate to 6 or seven digits", as such statements tend to propagate such "imprecise" beliefs. -------------------+------------------------------------------- Al Dunbar | Edmonton, Alberta | this space for rent CANADA | -------------------+-------------------------------------------
dbrooks@osf.org (David Brooks) (10/24/90)
In article <4032@goanna.cs.rmit.oz.au>, ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: |> |> The problem here is that a number like 0.64 *CANNOT* *POSSIBLY* be |> represented exactly in (finite-precision) floating-point. At all. |> In *any* programming language. Any compiler, any string->fp converter, |> is going to have to round nearly every number there is (only numbers |> which are an integer times a power of 2 are likely to be exact); some |> of them will round up and some of them will round down. Unless, of course, you are blessed with hardware that uses base 10 for its floating point. You are assuming as much about the internal representation of floating numbers as the original poster was. Are there any such machines around these days? -- David Brooks dbrooks@osf.org Systems Engineering, OSF uunet!osf.org!dbrooks That last signature was getting a little tired...
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (10/24/90)
In article <1990Oct23.191109@osf.org>, dbrooks@osf.org (David Brooks) writes: : In article <4032@goanna.cs.rmit.oz.au>, ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: : |> The problem here is that a number like 0.64 *CANNOT* *POSSIBLY* be : |> represented exactly in (finite-precision) floating-point. At all. : |> In *any* programming language. Any compiler, any string->fp converter, : |> is going to have to round nearly every number there is (only numbers : |> which are an integer times a power of 2 are likely to be exact); some : |> of them will round up and some of them will round down. : Unless, of course, you are blessed with hardware that uses base 10 for : its floating point. You are assuming as much about the internal : representation of floating numbers as the original poster was. Yes of *course* I was, because I was responding to the original poster. It's *his* hardware that counts, not some other hardware. It's his *software* that counts, too, not some other software. The original poster was complaining about what he thought was a bug in the C compilers available to him on the machines available to him. Those are the compiler and machine combinations that count when responding. If he had told us exactly which machines he was using, I'd have responded in terms of the FP formats of those specific machines. That's what he needed to know about. How would it help him to hear that some other kind of machine would do the job (B1800, and I think the B4800 as well, provided the program was rewritten in Fortran or Cobol)? I am amazed at the number of E-letters I've received from people who took it for granted that because I responded to the original poster in terms relevant to his query that I am ignorant of bignums, rationals, decimal floats, bigfloats, and the like. In each case I have implemented or been associated with the implementation of such things. They are of little interest to Joe Beginner trying to figure out how to use 'float' with C compiler X on machine Y. (A C++ programmer, now that's a different story.) -- Fear most of all to be in error. -- Kierkegaard, quoting Socrates.
bengsig@oracle.nl (Bjorn Engsig) (10/24/90)
Article <1990Oct23.191109@osf.org> by dbrooks@osf.org (David Brooks) says: |Unless, of course, you are blessed with hardware that uses base 10 for |its floating point. | |Are there any such machines around these days? Lots of them. Unfortunately, these handhelds don't run C :-) -- Bjorn Engsig, E-mail: bengsig@oracle.com, bengsig@oracle.nl ORACLE Corporation From IBM: auschs!ibmaus!cs.utexas.edu!uunet!oracle!bengsig "Stepping in others footsteps, doesn't bring you ahead"