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