1 |
Am 22.08.2015 um 15:43 schrieb Alan McKinnon: |
2 |
> On 22/08/2015 15:26, hw wrote: |
3 |
>> |
4 |
>> Hi, |
5 |
>> |
6 |
>> I have the following in a perl script: |
7 |
>> |
8 |
>> |
9 |
>> if ($a != $b) { |
10 |
>> print "e: '$a', t: '$b'\n"; |
11 |
>> } |
12 |
>> |
13 |
>> |
14 |
>> That will print: |
15 |
>> |
16 |
>> e: '69.99', t: '69.99' |
17 |
>> |
18 |
>> |
19 |
>> When I replace != with ne (if ($a ne $a) {), it doesn't print. |
20 |
>> |
21 |
>> |
22 |
>> Is that a bug or a feature? And if it's a feature, what's the explanation? |
23 |
>> |
24 |
>> And how do you deal with comparisions of variables when you get randomly |
25 |
>> either correct results or wrong ones? It's randomly because this |
26 |
>> statement checks multiple values in the script, and 69.99 is the only |
27 |
>> number showing up yet which isn't numerically equal to itself (but equal |
28 |
>> to itself when compared as strings). |
29 |
> |
30 |
> |
31 |
> |
32 |
> Computer languages have a much more exact idea of what equality means |
33 |
> than you do. In your head (because you are human, not silicon) you are |
34 |
> completely comfortable with taking "69.99" and treat8ing it as a string, |
35 |
> or a number, or a mostly-rounded-off floating point number. |
36 |
> |
37 |
> The computer does not do it like that. To a computer, the same must be |
38 |
> exactly the same. Two things a little bit different are completely |
39 |
> different (or not equal). And perl has two different operators for |
40 |
> (in)equality: |
41 |
> |
42 |
> != does a numerical comparison. More on this below |
43 |
> ne does a string comparison. When viewed as a bunch of characters, 69.99 |
44 |
> and 69.99 are identical. |
45 |
|
46 |
When the value is numerically not 69.99 but something like 69.99001, |
47 |
then printing the value should print 69.99001 rather than 69.99. |
48 |
|
49 |
perl -e 'print 1/3 . "\n";' prints 0.333333333333333 |
50 |
|
51 |
perl -e 'printf("%34.32f\n", 1/3);' prints |
52 |
0.33333333333333331482961625624739 |
53 |
|
54 |
perl -e 'print (((1/3 == 0.333333333333333) ? "equal" : "not equal") . |
55 |
"\n");' prints "not equal" |
56 |
|
57 |
perl -e 'print (((1/3 == 0.0.33333333333333331482961625624739) ? "equal" |
58 |
: "not equal") . "\n");' prints "Integer overflow in decimal number at |
59 |
-e line 1." a couple times |
60 |
|
61 |
This is random, may it be predictable or not, and what's the integer here? |
62 |
|
63 |
> Now, your comparisons are NOT random. They are entirely predictable, as |
64 |
> long as you know what is going on; you are running into floating point |
65 |
> numbers. And as it turns out, computers never represent these things |
66 |
> exactly (they are NOT integers). Even though they look identical |
67 |
> on-screen, in RAM they will not be (this must be so for perl to do the |
68 |
> print). Maybe they actually resolve to 69.990000001 and 69.99000000. You |
69 |
> see them as close-as-dammit equal, perl sees them as entirely different. |
70 |
|
71 |
Why can't it print the number as it is, or at least as it is compared, |
72 |
like it should? If it would, one could see at once what the problem is. |
73 |
|
74 |
> This is such as huge IT problem that many solutions have been proposed. |
75 |
> You get classes like BigFloat that represent a floating point as an |
76 |
> integer so that equality works, you can round the floats off before |
77 |
> comparing them, or just make the things integers. |
78 |
> |
79 |
> The last one is nice: don't represent money as dollars and cents, |
80 |
> represent it as cents or decicents and only divide by 100 (or 1000) when |
81 |
> you finally get to display it. |
82 |
|
83 |
That would add quite a lot of complexity, and the problem should either |
84 |
be handled transparently, or the value should be printed as the |
85 |
software/computer sees it. It is a recipe for disaster when you tell |
86 |
your computer to print something but it prints something else instead. |
87 |
|
88 |
> So how to fix your problem: you are doing what you shouldn't do - trying |
89 |
> equality on floats. Turn them into integers, or round them off, or use |
90 |
>> =/<= instead of != |
91 |
|
92 |
'=/<=' is not an operator in perl? |