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

I'm having a hard time understanding how this is happening. I have code that is doing a numerical comparison and I'm getting results I don't expect. The code looks like this:
if ($dollar1 != $dollar2) { print "$dollar1 != $dollar2\n"; }
and produces the following output:
5.35 != 5.35

How is this possible?

I'm reading the dollar amounts from a text file and I'm tempted to think that there is some sort of string comparison going on here but when I use != I expect to force the values to be compared as numbers.

What am I missing here?

Replies are listed 'Best First'.
Re: 5.35 != 5.35
by FunkyMonk (Bishop) on Feb 21, 2008 at 18:55 UTC
    Most floating point numbers (such as 5.35) aren't stored as exact values, just approximations. Use something like if ( abs($n1 - $n2) < 0.0001 ) { ... } to test for nearly equal.

    Depending on what it is you're trying to test, you may be able to use >= or <= instead.

    update:

    google has many links you can read for more details.

      Thanks for the help. I think I was stuck thinking down the line of it having something to do with type rather than something hidden.
Re: 5.35 != 5.35
by ikegami (Patriarch) on Feb 21, 2008 at 19:00 UTC

    To see the problem, add

    printf("%.16e\n", $dollar1); printf("%.16e\n", $dollar2);

    Never compare floating point numbers for equality. A lot of common numbers are periodic in binary so they cannot be stored exactly.

    >perl -le"printf '%.16e', 0.1" 1.0000000000000001e-001 ^ |

    You could round the number to two digits before comparing: (Probably should use something less expensive than sprintf)

    if (sprintf('%.2f', $dollar1) ne sprintf('%.2f', $dollar2)) { print "$dollar1 != $dollar2\n"; }

    You could work with cents instead of dollars. (Only convert back to dollars when printing)

    if ($cents1 != $cents2)) { print $cents1/100, ' != ', $cents2/100, "\n"; }
Re: 5.35 != 5.35
by kyle (Abbot) on Feb 21, 2008 at 18:55 UTC
Re: 5.35 != 5.35
by apl (Monsignor) on Feb 21, 2008 at 19:03 UTC
    You might want to read Why is Zero not 0?, especially as it references this article.

    You may want to store integer pennies rather than floating point dollars-and-cents.

Re: 5.35 != 5.35
by Fletch (Bishop) on Feb 21, 2008 at 19:01 UTC

    Phew! It'd been almost a week gone by without seeing someone baffled by the basic fact that IEEE floats aren't exact representations. I was starting to worry there for a bit.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      To be fair, the first time you encounter this error it is hard to find the issue unless you already know a bit about floating point numbers. The things you likely attribute it to and then search for aren't going to give you the answer (like in this case, where the suspected error was a type-mismatch).

      (I know you weren't mocking him, I just got started thinking on how hard this particular problem is for novices to diagnose if they don't already know the answer.)

Re: 5.35 != 5.35
by saberworks (Curate) on Feb 22, 2008 at 18:41 UTC
    If you're actually doing currency math, I would recommend using Math::Currency.
A reply falls below the community's threshold of quality. You may see it by logging in.