Re: floating point addition
by BrowserUk (Pope) on Jan 12, 2015 at 16:19 UTC

[0] Perl> printf "%20.17f\n", 20.1;;
20.10000000000000100
Then read:Re: Re: Re: Bug? 1+1 != 2.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks  Silence betokens consent  Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
 [reply] [d/l] 

Yeah, it never occurred to me to check that. Thanks.
 [reply] 
Re: floating point addition
by choroba (Bishop) on Jan 12, 2015 at 16:14 UTC

 [reply] [d/l] 

perl Mbignum e ' printf "%20.17f\n", 20.1;'
20.10000000000000142
perl Mbigrat e ' printf "%20.17f\n", 20.1;'
20.10000000000000142
perl Mbigrat e ' printf "%20.17f\n", 20+1/10;
20.00000000000000000
 [reply] [d/l] 

You are right about bignum. Your bigrat example, though, doesn't work. One needs
perl Mbigrat le 'print 20/1 + 1/10'
 [reply] [d/l] 




That I've stumbled upon myself, and it seems like an interesting article, however I'm a bit reluctant to read 67 pages of that just to reach the same conclusion I already know, avoid computers touching floating point numbers ...
A bit naive of me to think that 20.1 written like that means the same for a computer as it does to me.
 [reply] 

I think I detect a note of intended irony in that last sentence, but basically that's what you get when you try to do base 10 math in a base 2 machine. The sooner you become of aware of it, the sooner you can deal with it.
This part probably sounds like one of those tirades from old farts that begin "back in my day.." .. but .. back in my day, one of the required courses was "Programming for Numerical Methods" or some such title, and we spent the class trying to predict how poorly our computations would proceed based on understanding the limits of the algorithms. There were two results to each computation, the result and the error estimate, and the second result was more important because it told you if could take the first one seriously or not. I took the class in the 80's and our textbook dated back to the 60's. This has become less important over time because improvements in computational speed and memory allow us to use floating point numbers of sufficiently high resolution that we avoid a lot of these problems .. but here we are in 2015 and 1/10th is still giving us fits.
 [reply] 


 [reply] 

 [reply] 
Re: floating point addition
by davido (Archbishop) on Jan 12, 2015 at 16:55 UTC

If the floating point number cannot be represented precisely as n/(2^m) then it must be represented imprecisely in a binary form, and when that happens, rounding errors occur. In base ten, the formula is k/((2^n)*(5^m)). We're just more accustomed to the mental leap that 0.33 in base ten usually means 1/3rd, even though this is an imprecise representation of a nonterminating expansion. When we see the same thing in numbers that have lost precision due to being stored in base2, we panic. ;)
A few years ago I put together a more thorough explanation: Re: shocking imprecision
 [reply] [d/l] [select] 
Re: floating point addition
by hippo (Canon) on Jan 12, 2015 at 18:20 UTC

 [reply] 
Re: floating point addition
by trippledubs (Chaplain) on Jan 12, 2015 at 16:56 UTC

Another exercise to represent fractions in binary is to take the decimal and multiply by two in a column.
.625 * 2 = 1.25
.25 * 2 = 0.5
.5 * 2 = 1.0
Now taking the whole number and going from bottom to top you get 101, the binary representation, exactly.
If you take .1 you get
 .1 * 2 = 0.2
 .2 * 2 = 0.4
 .4 * 2 = 0.8
 .8 * 2 = 1.6
 .6 * 2 = 1.2
 .2 * 2 = 0.4
And from that point you get a repeating sequence in binary similar to .333..3 in decimal
And the takeaway is instead of testing for equality in floating point you test against an Epsilon (small quantity) and if the two numbers are within that Epsilon close to each other, they are for all intents are purposes, equal. Not doing so introduces bugs.
 [reply] 
Re: floating point addition
by LanX (Bishop) on Jan 12, 2015 at 18:16 UTC

 [reply] 

 [reply] 

 [reply] 

 [reply] 


Re: floating point addition
by sundialsvc4 (Abbot) on Jan 12, 2015 at 18:15 UTC

This is also the reason why processors have a “decimal mode,” in which both digits and the sign of the number are represented using fourbit groups (socalled “binarycoded decimal = BCD.”). The COBOL language is famous for exposing this feature, and for very obvious reasons: when dollarsandcents are involved, accountants (especially) care very much about “cents.” The arithmetic will be performed in true decimal mode, just like they taught you to do it byhand in grade school. (Uhhhhhh, back in my day, anyhow, when to use a pocket calculator was considered “cheating.”)
Perl does have a Math::Decimal package, which probably exposes the functionality that you might need here. (It says that it is “implemented mostly in XS,” but I have not taken the time to see whether it uses microprocessor decimalmath.) A package like this one will not be able to represent 1/3 exactly, simply because “base10 can’t do that,” but it will be able to represent 1/10 exactly.
Incidentally, if this is a design consideration, you must also use DECIMAL types in your databases, and be certain that the entire souptonuts handling of the numeric values does not ever stray into floatbinary. (You must also confirm that the underlying representation used by the database system in question is, in fact, decimal.) Databases may also offer a CURRENCY type that, in most cases, is actually a scaled binary integer. (Internally, the number is multiplied by 10,000 to give four fixed digits to the right of the decimal point.) Once again, you must ensure that the entire data productionline never wanders into floatbinary land.
Perl does have the capability to represent a value internally as a true integer, although the bitwidth of that integer may vary by implementation. Since it is a typeless language that tries its best to be accommodating, you must be mindful of exactly how Perl is representing and manipulating your values at all times ... if it matters. (As it certainly does, say when you are dealing with the final, doubleunderlined total at the bottom of a big, long invoice ...)
 [reply] 

It says that it is “implemented mostly in XS,” but I have not taken the time to see whether it uses microprocessor decimalmath
I don't think it does, but it certainly does decimal (as opposed to binary) arithmetic  and should be more than adequate for most people wanting to perform base 10 arithmetic.
OTOH, my Math::Decimal64 and Math::Decimal128 modules do make use of the _Decimal64 and _Decimal128 types, and associated operations:
C:\>perl MMath::Decimal64 le "$x=Math::Decimal64>new(0); $x += Math
+::Decimal64>new('20.1') for (1..43);print $x;"
8643e1
The user interface is a little awkward, mainly because gcc does not provide strtod64 or strtod128 functions, and does not provide any (s)printf formatters for the _Decimal64 and _Decimal128 type.
I'm working on improving that interface  and the current git version provides for output in floating point format instead of just scientific notation (ie as 864.3 instead of 8643e1 for the quoted example).
I must also add overloading of strings  so that the above one liner can be rewritten as:
perl MMath::Decimal64 le "$x=Math::Decimal64>new(0); $x += '20.1' f
+or (1..43);print $x;"
But I don't want to add overloading of NVs as that would defeat the purpose.
(That takes care of this month's quota of selfpromotion ;)
Cheers, Rob  [reply] [d/l] [select] 

But I don't want to add overloading of NVs as that would defeat the purpose.
How would this defeat the purpose?
 [reply] 
