#---Number---
Ruby provides robust support for working with numbers.
It can help with your numeric needs whether you make big integer amounts of fiat money or discrete fractional representations of crypto money. It doesn’t judge you.
+
-
/
*
%
p (11 + 2 - 3 * 4/5) % 6 # => 5
**
p "5^3 is #{5**3}" # => "5^3 is 125"
Note: The carat symbol ^
is used in Mathematics for
exponentiation. But in Ruby we use it for bitwise XOR.
For exponentiation, use **
.
p "bitwise 5^3 is #{5^3}"
## => "bitwise 5^3 is 6"
If you need accurate floating point arithmetic, you
should use the standard library’s BigDecimal
instead
of Float
.
p (4.3 - 4.1) == 0.2 # => false
require 'bigdecimal'
p (BigDecimal('4.3') - BigDecimal('4.1')) \
== BigDecimal('0.2') # true
With to_i
and to_f
methods, easily convert
between number types.
p 1/2 # => 0
p 1/(2.to_f) # => 0.5
But normally you don’t even have to do that. Ruby will infer the type based on the value.
p 84/2 # => 42 (Integer)
p 84.0/2 # => 42.0 (Float)
These are even available on strings!
p '3'.to_i # => 3
p '3.9'.to_i # => 3
p '3.9'.to_f # => 3.9
But be careful. Don’t trust these blindly.
p 'asdf3'.to_i # => 0
p '3asdf'.to_i # => 3
p '3.456asdf'.to_f # => 3.456
Use to_s
to convert any numeric type to string.
p 1_000_000.to_s # => "1000000"
All number types are Numeric
. And all numeric types
include the Comparable
module which gives the objects
of these types the ability to compare. Comparison
methods this module gives are:
==
<
>
<=
>=
p 5 > 4.3 # => true
It also gives the between?
and clamp
methods which
are neat. Can be used to set min, max limits.
p 5.between?(2, 10) # => true
p 42.clamp(1, 100) # => 42
p 101.clamp(1, 100) # => 100
p 0.clamp(1, 100) # => 1
Besides the above three, there are other methods such as
abs
, floor
, ceil
, round
, divmod
, next
pred
etc. There’s even a gcd
.
p -34.abs # => 34
p 34.93.floor # => 34
p 34.16.ceil # => 35
p 34.16.round # => 34
p 47.divmod(42) # => [1, 5]
p 100.next # => 101
p 100.pred # => 99
p 500.gcd(1000) # => 500
And also predicate methods like zero?
,
nonzero?
, positive?
, negative?
, integer?
,
finite?
, infinite?
, odd?
, even?
etc.
p 0.zero? # => true
p 5.even? # => false
p 5.odd? # => true
p 5.positive? # => true
p -5.negative? # => true
p Float::INFINITY.finite? # => false
The constants Float::INFINITY
and -Float::INFINITY
are used to represent the two ends of the extremes.
p 1_000_000 < Float::INFINITY # => true
p -Float::INFINITY < -1_000_000 # => true
p (1/0) rescue nil
## => 💥 blows up with: `ZeroDivisionError` error without
## `rescue nil`
p (1/0.0) # => Infinity
They’re also used in endless ranges.
p (1..4).count # => 4
p (1..).count # => Infinity
Numeric
is the parent class from which all these other
number-related classes inherit from.
Integer
p 1.class # => Integer
Float
p (3.14).class # => Float
Rational
p (1/3r).class # => Rational
Complex
p (1 + 2i).class # => Complex
Let’s explore the object/class hierarchy of numbers a bit:
p 2.is_a?(Integer) # => true
p 2.is_a?(Numeric) # => true
p 2.is_a?(Comparable) # => true
p 2.is_a?(Float) # => false
p 3.14.class.ancestors
##=>[Float, JSON::Ext::Generator::GeneratorMethods::Float,
## Numeric, Comparable, Object,
## JSON::Ext::Generator::GeneratorMethods::Object,
## PP::ObjectMixin, Kernel, BasicObject]
Before Ruby 2.4, the integers were represented using
these 2 Integer
sub-classes: Fixnum
and Bignum
.
But 2.4 got rid of them. Good riddance. Just use
Integer
and Float
now.
Since the number values are ruby objects, all the functionalities are available as methods on them instead of functions or operators like in most other languages.
The ability to call them without a dot and paranthesis is just a Ruby syntax sugar to make it seem elegant like operators.
That means 11 + 5
is actually 11.+(5)
. And
11 <= 12
is 11.<=(12)
:
p 11.+(5) # => 16
p 11.<=(12) # => true