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

I wrote a perl program that does some calculation on decimal numbers.

My input data looks like this:

............

20120620 093100 100000 84.02 84.09 83.59 83.60

20120621 093100 100000 80.67 80.96 80.35 80.43

20120622 093100 100000 78.71 79.10 78.43 79.09

20120625 093100 100000 79.04 79.09 78.28 78.43

............

I create an array (say @arr) that has each number from a line like above as its elements. Then I define my variables as follows:

$open= $arr[3];$high=$arr[4];$low=$arr[5];$close=$arr[6]; Then I do some calculations using these: The chunk of the code that does the calculation is: if ($close<$open) { $stretch=(($high*100)-($open*100)); $stretcher=(($open*100)-($low*100)); $identifier="Red"; } if ($close>$open) { $stretch=(($open*100)-($low*100)); $stretcher= (($high*100)-($open*100)); $identifier="Green"; } if ($close==$open) { $stretch=(($high*100)-($open*100)); $stretcher=(($open*100)-($low*100)); $identifier="Doji"; } print "$date $time1 $time2 $stretch $stretcher $identifier $open $high + $low $close\n";

My output is like this:

20120620 093100 100000 7 43 Red 84.02 84.09 83.59 83.60

20120621 093100 100000 28.9999999999991 32.0000000000009 Red 80.67 80.96 80.35 80.43

20120622 093100 100000 27.9999999999982 39 Green 78.71 79.10 78.43 79.09

20120625 093100 100000 4.99999999999909 76.0000000000009 Red 79.04 79.09 78.28 78.43

My questions are:

1) The first line of output is how I want each line of my output as. But that isnt so. Although the numbers that I am using for calculation in each of the above lines are almost similar, only the first line is giving me exact output. I want to know why this inconsistency is occurring here and how to rectify the errors.

2) It is unlikely that the error is because of the inherent issues with using decimal numbers in calculations since if that were the case, the first line of output must have been odd too. But that isnt the case. What exactly in perl causes this inconsistency? If it helps, how many ever times I run the program, the first line given here doesnt get odd, but the other lines always remain odd!

3) Of the numbers where output is odd, some have .99999999999 added and others have .00000000001 added. If I can at least make perl to give me numbers that are all appended with one among .999999999 or .000000000001, I will be okay since I can use ceiling or flooring function on the numbers.

Please help!!

Replies are listed 'Best First'.
Re: Decimal numbers calculations done inconsistently: Odd behavior!
by toolic (Bishop) on Mar 19, 2015 at 15:28 UTC
Re: Decimal numbers calculations done inconsistently: Odd behavior!
by atcroft (Abbot) on Mar 19, 2015 at 15:40 UTC
Re: Decimal numbers calculations done inconsistently: Odd behavior!
by LanX (Saint) on Mar 19, 2015 at 15:34 UTC
Re: Decimal numbers calculations done inconsistently: Odd behavior!
by Athanasius (Archbishop) on Mar 19, 2015 at 15:49 UTC

    Hello ferdi, and welcome to the Monastery!

    To expand a little on the answers given above: if you change the print statement to this:

    printf "%d %d %d %.15f %.15f %s %.0f %.0f %.0f %.0f\n", $date, $time1, $time2, $stretch, $stretcher, $identifier, $ope +n, $high, $low, $close;

    you will see:

    1:39 >perl 1187_SoPW.pl 20120620 93100 100000 7.000000000000000 43.000000000000000 Red 84 84 8 +4 84 20120621 93100 100000 28.999999999999091 32.000000000000909 Red 81 81 +80 80 20120622 93100 100000 27.999999999998181 39.000000000000000 Green 79 7 +9 78 79 20120625 93100 100000 4.999999999999091 76.000000000000909 Red 79 79 7 +8 78 1:40 >

    which shows why the numbers in the first line are printed as integers. One way to convert a floating-point number to the closest integer is to add 0.5 and then truncate:

    1:40 >perl -wE "my $fp = 28.999999999999091; my $int = int($fp + 0.5) +; say $int;" 29 1:47 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      This works well if you expect the floating point number to be near an integer. If you expect 3.5 to round to 4, it will fail if your 3.5 is really 3.49999999...
      Bill
        That may be slightly more complicated than that. IEEE Standard rounding rules are somewhat unexpected to many people. This is what true rounding is supposed to be according to IEEE:
        $ perl -e 'my $c = 0.5; $c +=1 and printf "%f -> %0.0f\n", $c, $c for +1..10;' 1.500000 -> 2 2.500000 -> 2 3.500000 -> 4 4.500000 -> 4 5.500000 -> 6 6.500000 -> 6 7.500000 -> 8 8.500000 -> 8 9.500000 -> 10 10.500000 -> 10
        Round up if the previous digit is odd and round down if it is even.

        Je suis Charlie.
Re: Decimal numbers calculations done inconsistently: Odd behavior!
by syphilis (Archbishop) on Mar 19, 2015 at 23:50 UTC
Re: Decimal numbers calculations done inconsistently: Odd behavior!
by Krambambuli (Curate) on Mar 20, 2015 at 09:35 UTC
    Since your decimals seem to always have exactly two fractional digits, it might suffice to "translate" everything into an 100x integer space. So you might write
    ($open, $high, $low, $close) = map { s/\.//; $_; } @arr[3, 4, 5, 6];
    and forget about the *100 multipliers in the following code.

    Of course, you'll have to add back the 'decimal dots' when outputting the results.

    ---
    Krambambuli