 go ahead... be a heretic PerlMonks

### Still puzzled by floats

by leriksen (Curate)
 on Oct 07, 2002 at 05:34 UTC Need Help??

leriksen has asked for the wisdom of the Perl Monks concerning the following question:

This question flows from an earlier problem I asked about summing to zero. Thanks for the replies.

Reading the perl FAQ, they state

However, 19.95 can't be precisely represented as a binary floating point number,...,

Why not? Surely there is a bit pattern in the IEEE float format that precisely represents 19.95 (1.995E1). If a float is stored in,say, 32 bits on a particulat platfrom, some bits are for the mantissa and some are for the exponent and sign. If 24 bits store the mantissa, isn't there a bit pattern from those 24 bits that precisely represents 1.995 ? Its not like it's a lot of precision.

If that is so, why can't the conversion library get that bit exact. The machine can represent 0.15 to however many decimal places it stores, why can't the conversion library create the correct representation? I understand that _expressions_ will potentially have inaccuracies, like exp(ln(x)) resulting in something very close but not quite x. But a string literal should (in my utopian view) convert precisely. The only exception to this would be a string literal expressing a value beyound the precision of the platform, OS or perl (most restrictive win's) - e.g. "0.1E-4096" will _probably_ end up being represented as 0.0E0

Is it related to the binary storage and summing fractional powers of 2 e.g. a2^-1 + b2^-2 + c2^-2 ... where a,b,c... are 1 or 0.

Anyone have a view why string literal conversion of seemingly inoccuous floats has inaccuracies?

Replies are listed 'Best First'.
Re: Still puzzled by floats
by blakem (Monsignor) on Oct 07, 2002 at 06:30 UTC
The decimal 0.95 can be represented in base 10 as:
```9/10 + 5/100
How would you represent that in binary?
```1/2 + 1/4 + 1/8 + 1/16 + 0/32 + 0/64 + 1/128 + 1/256 +
0/512 + 0/1024 + 1/2048 + 1/4096 ...
No matter how far you take that series it will *never* be exactly 0.95. The binary representation of 0.95 takes an infinite number of bits.

0.95(10) ≈ 0.1111 0011 0011 0011 0011 0011 0011(2)

But those last four bits repeat forever. Its exactly like writing 1/3 in base 10:

1/3 ≈ 0.33333333333333333333333333333333(10)

-Blake

Re: Still puzzled by floats
by hossman (Prior) on Oct 07, 2002 at 06:25 UTC

However, 19.95 can't be precisely represented as a binary floating point number,...,

Why not? Surely there is a bit pattern in the IEEE float format that precisely represents 19.95 (1.995E1). If a float is stored in,say, 32 bits on a particulat platfrom, some bits are for the mantissa and some are for the exponent...

That's not how it works.

What you are describing would be a base10 representation -- ie: you store a number and a base 10 exponent. What is typicaly used is a number and a base 2 exponent.

 what you want: mantissa * (10 ** exp) what you get: mantissa * (2 ** exp)

IEEE 854 specifies support for base10 representations, but no one uses it -- what gets used is IEEE 754. When you get a sizable chunk of free time, read through What Every Computer Scientist Should Know About Floating-Point Arithmetic -- in the mean time, John Darcy (Sun's floating point guru) has a great set of slides about Floats in java -- but the information is equally useful for perl programmers.

Re: Still puzzled by floats
by abell (Chaplain) on Oct 07, 2002 at 07:04 UTC

A little addition to what others already said: in base d you can only represent exactly numbers expressed by fractions a/b with b a divisor of some power of d. In other words, to check if a reduced fraction a/b is expressable in finite form (not periodic) in base d, all prime divisors of b must also divide the base d.

Thus, 13/24 has a finite form in base 6, since 24=2^3*3, and both 2 and 3 are factors of 6, but not in base 10 or 2. 1/2 has a finite form in base 2 and 10, but not 3 and so on.

Best regards

Antonio Bellezza

The stupider the astronaut, the easier it is to win the trip to Vega - A. Tucket
Re: Still puzzled by floats
by BrowserUk (Pope) on Oct 07, 2002 at 06:32 UTC

The simple answer is that some decimal fractions cannot be accurately representred by binary fractions for similar reason as some ordinary fractions cannot be represented using decimal fractions.

1/3 is an exact value, but the closest we can get to representing it as a decimal fraction is 0.3333333333333...

No matter how many 3's you add after the decimal point, you have never quite accurately represented it.

Update: I couldn't work out how to easily show what I was trying to show, and the other posts say what I was trying to illustrate better than I was going to anyway.

Cor! Like yer ring! ... HALO dammit! ... 'Ave it yer way! Hal-lo, Mister la-de-da. ... Like yer ring!
how about if you work the problem the other way.
Base 2 Base 10
----------------------------------------------
.0001 == 0/2 + 0/4 + 0/8 + 1/16 == .0625
.0010 == 0/2 + 0/4 + 1/8 + 0/16 == .125
.0011 == 0/2 + 0/4 + 1/8 + 1/16 == .1875
.0100 == 0/2 + 1/4 + 0/8 + 0/16 == .25
.0101 == 0/2 + 1/4 + 0/8 + 1/16 == .3125
.0110 == 0/2 + 1/4 + 1/8 + 0/16 == .375
.0111 == 0/2 + 1/4 + 1/8 + 1/16 == .4375
.1000 == 1/2 + 0/4 + 0/8 + 0/16 == .5
.1001 == 1/2 + 0/4 + 0/8 + 1/16 == .5625
.1010 == 1/2 + 0/4 + 1/8 + 0/16 == .625
.1011 == 1/2 + 0/4 + 1/8 + 1/16 == .6875
.1100 == 1/2 + 1/4 + 0/8 + 0/16 == .74
.1101 == 1/2 + 1/4 + 0/8 + 1/16 == .8125
.1110 == 1/2 + 1/4 + 1/8 + 0/16 == .875
.1111 == 1/2 + 1/4 + 1/8 + 1/16 == .9375

has you can see there are gaps in between the decimal numbers. The more accurate you want to get the more digits in the base 2 numbers you need. Assuming that you're working with a computer that has 32 bit registers you can only store a finite number so you may not always have enough bits to represent the fraction you want.

jjdraco
learning Perl one statement at a time.
Re: Still puzzled by floats
by maxomai (Initiate) on Oct 07, 2002 at 16:15 UTC
For what it's worth: you might be able to use Math::FixedPrecision to handle "floating point" data with as much precision as you need.

Generally speaking you probably want something that handles Binary Coded Decimals to handle decimal data flawlessly. Most Intel archtechtures and lots of (other) languages support BCD.

Hope this helps.

Re: Still puzzled by floats
by leriksen (Curate) on Oct 07, 2002 at 23:45 UTC
Thanx everyone, that was brilliant. I had the insight about infinite summation of fractional powers of two a couple of hours after I posted, but it's nice to see so many quality explanations and alternatives.

Create A New User
Node Status?
node history
Node Type: perlquestion [id://203251]
Approved by hossman
Front-paged by diotalevi
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (4)
As of 2020-10-29 18:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
My favourite web site is:

Results (274 votes). Check out past polls.

Notices?