Numeric comparison operators#
Seven operators that compare two numbers and return either a boolean (the first six) or a three-way result (<=>).
Operator | Question | Returns |
|---|---|---|
| less than | true / false |
| less or equal | true / false |
| equal | true / false |
| greater or equal | true / false |
| greater than | true / false |
| not equal | true / false |
| three-way (sort) |
|
All seven coerce both operands to numbers before comparing.
$age >= 18 # true if 18 or older
$count == 0 # true if numerically zero
$x != $y # true if they differ numerically
$a <=> $b # -1 if $a < $b, 0 if equal, +1 if $a > $b
== is for numbers, eq is for strings#
This is the single most common bug new Perl programmers ship. == compares numerically — both operands are run through numeric coercion, and any non-numeric string becomes 0:
"foo" == "bar" # TRUE -- both coerce to 0
"42x" == "42y" # TRUE -- both coerce to 42
"1e2" == 100 # TRUE -- "1e2" is 100 in scientific notation
For string equality, use eq:
"foo" eq "bar" # FALSE -- the actual question
"42x" eq "42y" # FALSE
If use warnings is in scope, the Argument "..." isn't numeric warning fires every time == (or any other numeric operator) sees a non-numeric string. That warning is your friend.
<=> — the spaceship operator#
<=> returns -1 if the left is smaller, 0 if equal, +1 if greater. It is the sort comparator:
my @sorted = sort { $a <=> $b } @numbers; # ascending
my @rev = sort { $b <=> $a } @numbers; # descending
# multi-key: by length, ties broken by content
my @lines = sort { length($a) <=> length($b) || $a cmp $b } @raw;
The pattern cmp1 || cmp2 || cmp3 works because <=> returns 0 on ties and || falls through on 0. See logical.
<=> and cmp are the only two operators on this family that are not boolean — they are integer-valued and exist for sorting, not for if-conditions.
Floating-point equality#
== on floats is exact bit-for-bit equality. For values produced by floating-point arithmetic this is almost never what you want:
0.1 + 0.2 == 0.3 # FALSE -- 0.30000000000000004
Compare with a tolerance:
abs($a - $b) < 1e-9 # absolute tolerance
abs($a - $b) < 1e-9 * abs($a) # relative tolerance, when $a ≠ 0
abs is a named-unary operator.
Chaining is not magic#
Perl does not support mathematical chaining of comparisons. $a < $b < $c does not test ”$b is between $a and $c“ — it parses as ($a < $b) < $c, where the first comparison yields a boolean ("" or 1) which is then numerically compared with $c:
1 < 5 < 3 # parses as (1 < 5) < 3
# = 1 < 3
# = TRUE -- which is *not* what you meant.
Write the conjunction explicitly:
$a < $b && $b < $c # the actual "between" test
Precedence#
Comparison operators sit at row 11 of the precedence table — looser than the arithmetic operators (so $a + $b == $c + $d works), tighter than the logical operators (so $a < $b && $c > $d works). They are non-associative: $a < $b < $c is not invalid, but the non-associativity warning explained above applies.
See also#
String comparison —
eq ne lt le gt ge cmp, the lexical-order family.Logical operators — combining comparison results.
<=>in sort — the canonical use case.Boolean Logic for Perl Programmers — the ”two flavours of comparison“ overview that motivates the numeric/string split.
Numbers and strings — when a scalar gets coerced to a number, and the precision/Inf/NaN story behind
==.