On 22/08/2015 16:57, hw wrote:
>
>
> 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.
I can't see your code and I don't know how you get values assigned to
those variables so I can't really give you an answer.
I can tell you that equality comparisons on floats are problematic, and
always will be due to how they are stored (double-precision floats,
inhernetly inexact). This is not a "problem" per se, it's a systemic
side effect of how our computers represent floats i.e. you can't "fix"
it as there is nothing to fix
Rob0t1's suggestion was the best, I'd forgotten that neat trick:
replace
if ($a != $b)
with
if ($a - $b <= $t)
where $t is an acceptable tolerance (0.001 in your case should be OK)
>
>> 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?
Oops. Mail-client mangling. The line started with ">" and the slash is or
It should read ">= or <="
--
Alan McKinnon
[email protected]