Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Re: Re: Filthy Floats

by TheoPetersen (Priest)
on Jul 16, 2001 at 20:38 UTC ( [id://97078]=note: print w/replies, xml ) Need Help??


in reply to Re: Filthy Floats
in thread Filthy Floats

The problem isn't in ActiveState's product or Microsoft's (but feel free to blame Microsoft anyway; I use them as a general blame sink). The problem is that floating point values do not represent exact decimal numbers. If you want exact decimal numbers, use integers to represent them and then shift the decimal point to the correct position.

You'll find most database products offer to do this for you. Unfortunately when copying the stored value from the database to Perl, it gets stored as a floating point value again. To preserve accuracy you need to keep the value as an integer until it presentation.

Replies are listed 'Best First'.
Re: Re: Re: Filthy Floats
by THuG (Beadle) on Jul 16, 2001 at 21:01 UTC

    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?

      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

      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.
      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.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://97078]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (8)
As of 2024-04-16 18:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found