http://qs321.pair.com?node_id=97088


in reply to Re: Re: Filthy Floats
in thread Filthy Floats

Okay, I went to University for a BS in Computer Science, so I understand the idea behind floating point representation (and single and double precision, and underflow errors).

But I am finding it hard to believe that Perl can't represent 0.98. So I did a little test. The DB field is set to string and it is literally ".98". I can pull it from the DB and when I go to display it, I make sure it is displayed as a numerical value and not a string (<%=$target * 1%>).

If I leave the * 1 out, it shows the string as it is in the DB ".98". If I put the * 1 in, it shows the value "0.98".

Is Perl doing some magic and not treating ".98" as a float when it needs to computer it with an integer? I figured I would try * 0.5 instead of * 1. Guess what, I get "0.49".

Is Perl doing that much magic, or can it represent 0.98 as a single or double float?

Replies are listed 'Best First'.
Re: Re: Re: Re: Filthy Floats
by nardo (Friar) on Jul 16, 2001 at 23:34 UTC
    I am finding it hard to believe that Perl can't represent 0.98

    printf("%.25f\n", 0.98);
    It's not perl, it's the underlying floating points which can not precisely represent 0.98, this is due to floating point numbers being base 2 and having a finite size.
Re: Re: Re: Re: Filthy Floats
by John M. Dlugosz (Monsignor) on Jul 17, 2001 at 01:41 UTC
    Perl 6 will have "big rats" that will represent 98/100 exactly. For now, you can use ints and do it yourself. Are you doing arithmetic on the value you fetch? I assume so, or it would not be converted from a string to a number. So, fetch the value, and use a regex to remove the decimal point and note how many digits were to the right of it originally. Now value X becomes (Y*Z) where Y is your integer and Z is the implicit power of ten. Do your math with Y, and also see what becomes of Z in the formulas but keep it implicit. When displaying stick the decimal in the string based on Z, but don't divide.

      Well, I'm getting the number from the DB, and then multiplying it against another number, modifying the other number. And then I'm displaying the number.

      It was treated as a number at some point in its history, even though I'm displaying it as a string and not really doing any math to it when I display it.

      Anyway, its all been resolved. At some point it is being converted to a single and Perl assumes those digits are significant. If I could pull the double from the DB and use it as a double I would be happy, but even if it is set as a double, it still becomes a single.

Re: Re: Re: Re: Filthy Floats
by TheoPetersen (Priest) on Jul 16, 2001 at 21:09 UTC
    Perl does lots of magic, especially in the way it handles scalars as strings, integers and floats simultaneously.

    In your case, the value is being handled as a string until you force Perl to treat it as a number (by using it in a multiplication). The result is a floating point value, subject to the inaccuracies described elsewhere. If it comes up with a seemingly exact value sometimes, well, welcome to the mystery :)

    I take it the issue here is that you want a leading zero, or some other normalization? If so, then use sprintf to enforce the format you want. Try <%=sprintf("%1.2f",$target)%> for instance.

      No, I don't want normalization, what I want is the number that was put into the DB. If they put in .98, then I want .98. If they put in .97062, then that's what I want.

      If I give Perl .98 as a string and then coherce it into a float, it has no problem representing it. I simply fail to believe that there is a floating point precision problem within Perl that should be accepted in this case. There may be one in Access, or in the ODBC magic that is handing the data to Perl from the DB. In other words, if there is a floating point problem, it is correctable on some level.

      -Travis

        Then store the value as a string, an integer, or something else that will remain exact. If you put it in a floating point value (in Perl, Access, ODBC or whatever) then you will not get the exact value back, except in cases where the binary and decimal representations have the same value (such as zero).

        As to the second point, this is not correctable, on any level. You can get closer to exact values by using more bits (thus the attraction of double over float) but the phenomenon is inherent to floating point representation in binary, not to any of the languages mentioned.