can long double be less precise than double?
Author |
Message |
A. Ap #1 / 11
|
can long double be less precise than double?
Hi, i have a problem with using long double: long double x,y,ymin=0.45,ystep=0.05; y=0.45+0.05; x = (y>0.5) ? (y-1) : y; printf("x=%Lf\n",x); /* this part gives, as expected, x = 0.5 */ y=ymin+ystep; x = (y>0.5) ? (y-1) : y; printf("x=%Lf\n",x); /* this part gives x = -0.5 !!!! */ If i change the type from long double to double, i get the expected result which is 0.5 in both cases. i simply do not understand what is going on... don't even know where the problem might be. (running Linux 2.2.17; processor Pentium III; output of gcc -v : Reading specs from /usr/lib/gcc-lib/i386-slackware-linux/egcs-2.91.66/specs gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) ) thanks in advance, -amit. --
|
Sat, 15 Jan 2005 06:15:51 GMT |
|
|
Erik Max Franci #2 / 11
|
can long double be less precise than double?
Quote:
> i simply do not understand what is going on... don't even know where > the problem might be.
The problem is that floating point arithmetic is inherently inaccurate. If you need to do comparisons between floating point numbers, you should be doing it with buffering values, e.g., instead of x == y, you should test abs(x - y) < x*epsilon, with epsilon an appropriately-chosen and small constant. --
__ San Jose, CA, US / 37 20 N 121 53 W / ICQ16063900 / &tSftDotIotE / \ See the son in your bad day / Smell the flowers in the valley \__/ Chante Moore Bosskey.net: Aliens vs. Predator 2 / http://www.bosskey.net/avp2/ A personal guide to Aliens vs. Predator 2. --
|
Sun, 16 Jan 2005 00:51:36 GMT |
|
|
Jack Klei #3 / 11
|
can long double be less precise than double?
comp.lang.c.moderated: In regards to your the question you asked in the subject line and neglected to repeat in the body, no. Quote: > Hi, i have a problem with using long double: > long double x,y,ymin=0.45,ystep=0.05; > y=0.45+0.05; x = (y>0.5) ? (y-1) : y; > printf("x=%Lf\n",x); > /* this part gives, as expected, x = 0.5 */ > y=ymin+ystep; x = (y>0.5) ? (y-1) : y; > printf("x=%Lf\n",x); > /* this part gives x = -0.5 !!!! */ > If i change the type from long double to double, i get the expected > result which is 0.5 in both cases. > i simply do not understand what is going on... don't even know where > the problem might be. > (running Linux 2.2.17; processor Pentium III; output of gcc -v : > Reading specs from > /usr/lib/gcc-lib/i386-slackware-linux/egcs-2.91.66/specs > gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) > ) > thanks in advance, > -amit.
What makes you think this has anything to do with precision? It has to do with rounding of floating point types. Any elementary treatment of floating point calculations on digital computers should clear it up. -- Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq --
|
Sun, 16 Jan 2005 00:52:08 GMT |
|
|
Pierre Asseli #4 / 11
|
can long double be less precise than double?
Quote: >long double x,y,ymin=0.45,ystep=0.05; >y=0.45+0.05; x = (y>0.5) ? (y-1) : y;
0.45 and 0.05 are not representable exactly as binary fractions. In infinite precision y would be 0.5, hence (y>0.5) would be false, but in finite precision y picks up 3 roundoff errors, whose net sign depends on the fraction length. Note also that your constants 0.45 and 0.05 are double, not long double. What's the syntax already? 0.45L ? Hmmm, your code might actually guarantee y==0.5 if you take care to use long double constants, but it would be a really tricky case. --
|
Sun, 16 Jan 2005 00:52:16 GMT |
|
|
jacob navi #5 / 11
|
can long double be less precise than double?
Quote: > Hi, i have a problem with using long double: > long double x,y,ymin=0.45,ystep=0.05;
Under the windows OS and using the lcc-win32 compiler I see: ymin +4.50000000000000011e-0001 ystep +5.00000000000000030e-0002 Why? Because YOU FORGOT THE 'L' AFTER THE CONSTANTS!!!!!! You should have written: Quote: > long double x,y,ymin=0.45L,ystep=0.05L;
If you do NOT write the L the compiler reads a double precision constant and then converts it to long double precision. The bits 53-63 of the mantissa are now RANDOM RUBBISH! --
|
Sun, 16 Jan 2005 00:52:24 GMT |
|
|
Hans-Bernhard Broeke #6 / 11
|
can long double be less precise than double?
Quote:
> Hi, i have a problem with using long double: > long double x,y,ymin=0.45,ystep=0.05; > y=0.45+0.05; x = (y>0.5) ? (y-1) : y; > printf("x=%Lf\n",x); > /* this part gives, as expected, x = 0.5 */
If this is what you expect, your expectation is at least slightly incorrect. As the saying goes: In computing, 10.0 times 0.1 is hardly ever 1.0 Or, to put the same warning in different words: *Never* trust the last digit of any floating point result. You assume that the result of the computation of y is exactly 0.5000000... to the very last representable digit, and since that violates the above rule, your expecatation breaks down. It's purely luck (and some of the more didactically minded people here would insist that it's *bad* luck) that your expectation was fulfilled in this case. You're making it worse because you store double-precisition floating point constants in (potentially) higher-precision variables. You should be using long-double constants instead: long double x, y, ymin=0.45L, ystep=0.05L; y=0.45L+0.05L; x = (y > 0.5L) ? (y - 1.0L) : y; y = 0.45L + 0.05L --
Even if all the snow were burnt, ashes would remain. --
|
Sun, 16 Jan 2005 00:52:31 GMT |
|
|
Toby Speigh #7 / 11
|
can long double be less precise than double?
AA> long double x,y; AA> AA> y=0.45+0.05; x = (y>0.5) ? (y-1) : y; AA> printf("x=%Lf\n",x); AA> /* this part gives, as expected, x = 0.5 */ AA> AA> y=ymin+ystep; x = (y>0.5) ? (y-1) : y; AA> printf("x=%Lf\n",x); AA> /* this part gives x = -0.5 !!!! */ AA> AA> If i change the type from long double to double, i get the expected AA> result which is 0.5 in both cases. I'm not sure why you expected 0.5, because 0.45 and 0.05 are not exactly representable in binary fractions. There are three possibilities: a. 0.45 and 0.05 both round to a binary fraction that's slightly lower than the exact value - the sum will be less than 0.5 and you'll get your "expected" result. b. 0.45 and 0.05 round in opposite directions, and sum to exactly 0.5 - you'll get your "expected" result. c. 0.45 and 0.05 both round up, summing to something slightly greater than 0.5, and you'll be surprised. Whether each value rounds up or down depends on the value of the first omitted bit, and therefore on the number of bits of precision. The absolute error of each summand will get lower as you reduce the precision, but the error of the total will sometimes be exactly zero, and sometimes greater. This is the reason you shouldn't write code like for (i=0.0; i!=1.0; i+=0.1) do_something(); Or is your confusion simply due to the fact that printf doesn't give an exact result in decimal? That the value of x in the second case is slightly higher (less negative) than -0.5, but the difference is way down in the least significant bit that's not printed? And that the first case may or may not be slightly less than 0x5, but you can't tell from the printout? --
|
Sun, 16 Jan 2005 00:52:36 GMT |
|
|
Thad Smit #8 / 11
|
can long double be less precise than double?
Quote:
> Hi, i have a problem with using long double: > long double x,y,ymin=0.45,ystep=0.05; > y=0.45+0.05; x = (y>0.5) ? (y-1) : y; > printf("x=%Lf\n",x); > /* this part gives, as expected, x = 0.5 */ > y=ymin+ystep; x = (y>0.5) ? (y-1) : y; > printf("x=%Lf\n",x); > /* this part gives x = -0.5 !!!! */ > If i change the type from long double to double, i get the expected > result which is 0.5 in both cases.
There are two issues here: 1. results of rounding inexact representations 2. difference between compile time and run time evaluation. The exact arithmetic value of 0.45 + 0.05 is 0.5, which causes (y>0.5) to evaluate false, since y is equal to, not greater than 0.5. The first approximation to (y>0.5) is thus false. Floating point in most computers uses binary notation for the mantissa, resulting in many numbers not having an exact representation, including 0.45 and 0.05. They are rounded, in some fashion, to a nearby value which is representable. When two floating point numbers are added, the results are also rounded, in some fashion, to a representable number. In the first case, the evaluated sum was rounded to a value larger than 0.5, giving you the results you expected. In the second case, sum was rounded to a value 0.5 or less, giving you different results. Both results should be very very close to each other. Small rounding errors are normal for floating point arithmetic. The reason why the results are different is apparently that the first expression is evaluated when the program is compiled, since the compiler knows both operands. The technique it uses for rounding of the results differs from the evaluation at run time. This is normally a quality of implementation issue, i.e., better implementations should, IMO, give the same results in both cases, assuming that the rounding mode is not explicitly changed. In summary, the results you got are acceptable, as a slight and expected difference in rounding can make (y>0.5) evaluate as either true or false. Thad --
|
Sun, 16 Jan 2005 00:52:41 GMT |
|
|
Kevin D. Quit #9 / 11
|
can long double be less precise than double?
No, but it can be less accurate. Note that 0.45 is not exactly representable in floating point. ftp://ftp.quitt.net/Outgoing/goldbergFollowup.pdf -- #include <standard.disclaimer> _ Kevin D Quitt USA 91351-4454 96.37% of all statistics are made up Per the FCA, this email address may not be added to any commercial mail list --
|
Sun, 16 Jan 2005 23:11:08 GMT |
|
|
Rob #10 / 11
|
can long double be less precise than double?
Quote: > Hi, i have a problem with using long double: > long double x,y,ymin=0.45,ystep=0.05; > y=0.45+0.05; x = (y>0.5) ? (y-1) : y; > printf("x=%Lf\n",x); > /* this part gives, as expected, x = 0.5 */ > y=ymin+ystep; x = (y>0.5) ? (y-1) : y; > printf("x=%Lf\n",x); > /* this part gives x = -0.5 !!!! */ > If i change the type from long double to double, i get the expected > result which is 0.5 in both cases. > i simply do not understand what is going on... don't even know where > the problem might be. > (running Linux 2.2.17; processor Pentium III; output of gcc -v : > Reading specs from > /usr/lib/gcc-lib/i386-slackware-linux/egcs-2.91.66/specs > gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) > )
This isn't a problem of different precision. It's a problem caused by the fact that *no* floating point representation is precise. In any floating point scheme, 0.05 and 0.45 can not be represented exactly. Try to represent those values in base 2 and you'll find you can't do it exactly. Since both values will be stored inexactly, their sum is also likely to be inexact, i.e. different from 0.5 (although you may get lucky and the errors cancel out on addition). You just got lucky when your first example gave what you expected. With different machines or compilers (associated with different floating point representations) you could get lucky (or unlucky depending on how you look at it) with both examples. --
|
Sun, 16 Jan 2005 23:11:27 GMT |
|
|
A. Ap #11 / 11
|
can long double be less precise than double?
Thanks a lot for the responses. i understand it wasn't a very well thought out question..., amit --
|
Mon, 17 Jan 2005 02:25:19 GMT |
|
|
|