Am 22.08.2015 um 15:43 schrieb Alan McKinnon:
On 22/08/2015 15:26, hw wrote:

Hi,

I have the following in a perl script:


       if ($a != $b) {
         print "e: '$a', t: '$b'\n";
       }


That will print:

e: '69.99', t: '69.99'


When I replace != with ne (if ($a ne $a) {), it doesn't print.


Is that a bug or a feature?  And if it's a feature, what's the explanation?

And how do you deal with comparisions of variables when you get randomly
either correct results or wrong ones?  It's randomly because this
statement checks multiple values in the script, and 69.99 is the only
number showing up yet which isn't numerically equal to itself (but equal
to itself when compared as strings).



Computer languages have a much more exact idea of what equality means
than you do. In your head (because you are human, not silicon) you are
completely comfortable with taking "69.99" and treat8ing it as a string,
or a number, or a mostly-rounded-off floating point number.

The computer does not do it like that. To a computer, the same must be
exactly the same. Two things a little bit different are completely
different (or not equal). And perl has two different operators for
(in)equality:

!= does a numerical comparison. More on this below
ne does a string comparison. When viewed as a bunch of characters, 69.99
and 69.99 are identical.

When the value is numerically not 69.99 but something like 69.99001, then printing the value should print 69.99001 rather than 69.99.

perl -e 'print 1/3 . "\n";' prints 0.333333333333333

perl -e 'printf("%34.32f\n", 1/3);' prints 0.33333333333333331482961625624739

perl -e 'print (((1/3 == 0.333333333333333) ? "equal" : "not equal") . "\n");' prints "not equal"

perl -e 'print (((1/3 == 0.0.33333333333333331482961625624739) ? "equal" : "not equal") . "\n");' prints "Integer overflow in decimal number at -e line 1." a couple times

This is random, may it be predictable or not, and what's the integer here?

Now, your comparisons are NOT random. They are entirely predictable, as
long as you know what is going on; you are running into floating point
numbers. And as it turns out, computers never represent these things
exactly (they are NOT integers). Even though they look identical
on-screen, in RAM they will not be (this must be so for perl to do the
print). Maybe they actually resolve to 69.990000001 and 69.99000000. You
see them as close-as-dammit equal, perl sees them as entirely different.

Why can't it print the number as it is, or at least as it is compared, like it should? If it would, one could see at once what the problem is.

This is such as huge IT problem that many solutions have been proposed.
You get classes like BigFloat that represent a floating point as an
integer so that equality works, you can round the floats off before
comparing them, or just make the things integers.

The last one is nice: don't represent money as dollars and cents,
represent it as cents or decicents and only divide by 100 (or 1000) when
you finally get to display it.

That would add quite a lot of complexity, and the problem should either be handled transparently, or the value should be printed as the software/computer sees it. It is a recipe for disaster when you tell your computer to print something but it prints something else instead.

So how to fix your problem: you are doing what you shouldn't do - trying
equality on floats. Turn them into integers, or round them off, or use
=/<= instead of !=

'=/<=' is not an operator in perl?

Reply via email to