A faster way to check the sign of a number in Ruby on Rails

Ruby has two methods for checking the sign of a number: positive? and negative?. These methods were introduced in Ruby 2.3, and they provide a more concise and readable way to check the sign of a number than using comparison operators.

Comparison operators

The traditional way to check the sign of a number in Ruby is to use comparison operators. For example, the following code checks if the number is positive:

1
2
3
4
5
6
7
8
9
number = 10

if number > 0
  puts "The number is positive."
else
  puts "The number is negative."
end

#=> The number is positive.

However, this code can be confusing, especially if you are not familiar with the order of operations in Ruby. For example, the following code will also output the same result:

1
2
3
4
5
6
7
number = 10

if number >= 0
  puts "The number is positive."
else
  puts "The number is negative."
end

This is because the >= operator is evaluated before the >> operator.

positive? and negative?

The positive? and negative? methods provide a more concise and readable way to check the sign of a number. The more English-like version of your code will be more intuitive and easier to understand when you come back to it later For example, the following code is equivalent to the previous code that uses comparison operators:

1
2
3
4
5
6
7
8
9
number = 10

if number.positive?
  puts "The number is positive."
else
  puts "The number is negative."
end

#=> The number is positive.

The positive? method returns true if the number is positive, and false otherwise. The negative? method returns true if the number is negative, and false otherwise.

Performance

In some cases, using positive? and negative? can also improve performance. For example, the following code will print the number of positive numbers in an array:

1
2
3
4
5
6
7
numbers = [1, 2, -3, 4, 5]

positive_count = numbers.count { |number| number > 0 }

puts positive_count

#=> 3

However, this code can be inefficient, because it uses a for loop to iterate through the array. The following code is more efficient because it uses the positive? method:

1
2
3
4
5
6
7
numbers = [1, 2, -3, 4, 5]

positive_count = numbers.count(&:positive?)

puts positive_count

#=> 3

The count(&:positive?) method uses the positive? method to filter the array, which can be more efficient than using a for loop.

These methods are optimized for speed, while the comparison operators > and <= are not.

1
2
3
4
5
6
7
8
9
10
require "benchmark/ips"

Benchmark.ips do |x|
  x.report("5 > 0") { 5 > 0 } #=> true
  x.report("0 > 0") { 0 > 0 } #=> false
  x.report("-5 > 0") { -5 > 0 } #=> false
  x.report("5.positive?") { 5.positive? } #=> true
  x.report("0.positive?") { 0.positive? } #=> false
  x.report("-5.positive?") { 5.positive? } #=> false
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Calculating -------------------------------------
               5 > 0   329.619k i/100ms
               0 > 0   317.684k i/100ms
              -5 > 0   316.506k i/100ms
         5.positive?   314.082k i/100ms
         0.positive?   301.732k i/100ms
        -5.positive?   284.074k i/100ms
-------------------------------------------------
         5 > 0     19.609M (± 4.6%) i/s -     97.897M
         0 > 0     20.511M (± 2.3%) i/s -    102.612M
        -5 > 0     19.483M (± 8.2%) i/s -     96.218M
   5.positive?     15.525M (± 2.6%) i/s -     77.578M
   0.positive?     15.251M (± 4.8%) i/s -     76.338M
  -5.positive?     14.733M (± 5.4%) i/s -     73.291M

positive? and negative? are a useful addition to the Ruby language. They provide a more concise and readable way to check the sign of a number, and they can also improve performance in some cases.