Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

IEEE-754 calculation - best way?

by Biker1971 (Initiate)
on Jan 30, 2013 at 21:56 UTC ( #1016160=perlquestion: print w/replies, xml ) Need Help??
Biker1971 has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I'm trying to calculate some values in the IEEE 754 format, incl. the restrictions of accuracy. For example, if I multiply 0.29 with 50, I get 14.5:
my $num1 = 0.29; my $num2 = 50; my $num3 = $num1 * $num2; print "num3=$num3\n"; # is '14.5'
Only with this line:
my $num4 = sprintf ("%.64f", $num7);
I get the exact result in "double" (14.999...). Is there are way to enable to get the same result without the sprintf instruction? Also if I use "eval", the result differs from the IEEE-754 calculation. What I want to do is to calculate everything with IEEE-754 numbers ("double" in C).
my $num1 = 0.29; my $num2 = sprintf ("%.64f", $num1); my $num3 = 50; my $num4 = sprintf ("%.64f", $num3); my $num5 = $num2 * $num4; my $num6 = sprintf ("%.64f", $num5); my $num7 = $num1 * $num3; my $num8 = sprintf ("%.64f", $num7); my $num9 = eval(eval($num1) * eval($num3)); my $num10 = sprintf ("%.64f", $num9); results in num1=0.29 num2=0.2899999999999999800159855567471822723746299743652343750000... num3=50 num4=50.000000000000000000000000000000000000000000000000000000000... num5=14.5 num6=14.499999999999998223643160599749535322189331054687500000000... num7=14.5 num8=14.499999999999998223643160599749535322189331054687500000000... num9=14.5 num10=14.50000000000000000000000000000000000000000000000000000000...

Replies are listed 'Best First'.
Re: IEEE-754 calculation - best way?
by BrowserUk (Pope) on Jan 30, 2013 at 22:40 UTC
    if I multiply 0.29 with 50, I get 14.5: Only with this line: my $num4 = sprintf ("%.64f", $num7); I get the exact result in "double" (14.999...).

    The only difference between:

    print 0.29 * 50;; 14.5


    printf "%.20f\n", 0.29 * 50;; 14.49999999999999800000

    is what gets printed out; not what is calculated and stored internally.

    All floating point calculations are done internally using IEEE754 semantics; if you want to see the full internal results use printf to display the results.

    As for your perceived difference when gratuitously using eval:

    printf "%.20f\n", eval eval( 0.29 ) * eval( 50 );; 14.50000000000000000000

    The first thing to note is that the first two evals make no difference whatsoever:

    printf "%.20f\n", eval 0.29 * 50;; 14.50000000000000000000

    And the reason for that difference is because (in this form) eval expects a string. So the result of the multiplication (eval( 0.29 ) * eval( 50 )) is converted to a string -- using the same rules as print -- before being passed to the final eval.

    You get identically different results if you do:

    $n = 0.29 * 50; printf "%.20f\n", "$n";; 14.50000000000000000000

    Because the internal (IEEE754) representation has been lost by the conversion to a string.

    Bottom line: Stop worrying about it. Do your floating point math in the usual way (no eval's; no stringifications), secure in the full IEEE754 semantics will be used internally; and then use printf/sprintf (*only*) when you need to display them.

    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".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: IEEE-754 calculation - best way?
by dave_the_m (Prior) on Jan 30, 2013 at 22:27 UTC
    In perl, all fractional numbers, and most operations on them, are performed internally using "C" doubles. The artefacts you are seeing are from when you ask perl to convert that value into a string (e.g. with print, or when you try to eval a string). When perl stringifies a number, it does it to a particular default precision, for example to 15 decimal places. If you don't like this default, then yes, you'll need to use sprintf or similar.


Re: IEEE-754 calculation - best way?
by Illuminatus (Curate) on Jan 30, 2013 at 22:31 UTC
    This is really 2 questions
    1. How do I calculate values all adhering to IEEE-754?
    2. How do I display an IEEE-754 value accurately?
    Perl uses double or long double as its internal data format, depending on how it's built. It's going to do 754-compliant calculations.

    The only way you can control how the value is displayed is via a mechanism that allows you to specify what you want. Things like printf/fprintf/sprintf (or something like Number::Format).


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1016160]
Approved by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2018-05-20 13:46 GMT
Find Nodes?
    Voting Booth?