Ruby includes five built-in classes for representing numbers, and the standard library includes three more numeric classes that are sometimes useful. Figure 3-1 shows the class hierarchy.
All number objects in Ruby are instances of Numeric
. All integers are instances of
Integer
. If an
integer value fits within 31 bits (on most implementations), it is an
instance of Fixnum
. Otherwise, it is a Bignum
.
Bignum
objects represent integers of
arbitrary size, and if the result of an operation on Fixnum
operands is too big to fit in a
Fixnum
, that result is transparently
converted to a Bignum
. Similarly, if
the result of an operation on Bignum
objects falls within the range of Fixnum
, then the result is a Fixnum
. Real numbers are
approximated in Ruby with the Float
class, which uses the native floating-point representation of the
platform.
The Complex
class
represents complex numbers, of course. BigDecimal
represents
real numbers with arbitrary precision, using a decimal representation
rather than a binary representation. And Rational
represents
rational numbers: one integer divided by another. In Ruby 1.8 these
classes are in the standard library. In Ruby 1.9, Complex
and Rational
are built-in.
All numeric objects are immutable; there are no methods that
allow you to change the value held by the object. If you pass a
reference to a numeric object to a method, you need not worry that the
method will modify the object. Fixnum
objects are commonly used, and Ruby implementations typically treat them
as immediate values rather than as references. Because numbers are
immutable, however, there is really no way to tell the
difference.
An integer literal is simply a sequence of digits:
0 123 12345678901234567890
If the integer values fit within the range of the Fixnum
class, the
value is a Fixnum
. Otherwise, it is a Bignum
, which supports integers of any size.
Underscores may be inserted into integer literals (though not at the
beginning or end), and this feature is sometimes used as a thousands
separator:
1_000_000_000 # One billion (or 1,000 million in the UK)
If an integer literal begins with zero and has more than one
digit, then it is interpreted in some base other than base 10. Numbers
beginning with 0x
or 0X
are hexadecimal (base 16) and use the
letters a
through f
(or A
through F) as digits for 10 through 15. Numbers beginning 0b
or 0B
are binary (base 2) and may only include digits 0
and 1
.
Numbers beginning with 0
and no
subsequent letter are octal (base 8) and should consist of digits between 0
and 7
.
Examples:
0377 # Octal representation of 255 0b1111_1111 # Binary representation of 255 0xFF # Hexadecimal representation of 255
To represent a negative number, simply begin an integer literal with a minus sign. Literals may also begin with a plus sign, although this never changes the meaning of the literal.
A floating-point literal is an optional sign followed by one or more decimal
digits, a decimal point (the .
character), one or more additional digits, and an optional exponent.
An exponent begins with the letter e
or E
,
and is followed by an optional sign and one or more decimal digits. As
with integer literals, underscores may be used within floating-point literals. Unlike integer
literals, it is not possible to express floating-point values in any
radix other than base 10. Here are some examples of floating-point
literals:
0.0 -3.14 6.02e23 # This means 6.02 × 1023 1_000_000.01 # One million and a little bit more
Ruby requires that digits appear before and after the decimal
point. You cannot simply write .1
,
for example; you must explicitly write 0.1
. This is necessary to avoid ambiguity in
Ruby’s complex grammar. Ruby differs from many other languages in this
way.
All numeric types in Ruby define standard +
, –
, *
,
and /
operators for addition, subtraction, multiplication, and
division. When an integer result is too large for a Fixnum
, Ruby automatically converts to a Bignum
, and as a
result, integer arithmetic in Ruby never overflows as it does in many
other languages. Floating-point numbers (at least on platforms that
use the standard IEEE-754 floating-point representation) overflow to
special positive or negative infinity values, and underflow to
zero.
The division operator depends on the class of the operands:
if both operands are integers, then truncating integer
division is performed. If either operand is a Float
, then floating-point division is
performed. There are also three division methods: div
performs integer division, fdiv
performs floating-point division, and
quo
returns a Rational
when possible, and otherwise
returns a Float
(this requires the
“rational” module in Ruby 1.8):
[5/2, 5.0/2, 5/2.0] # => [2, 2.5, 2.5] [5.0.div(2), 5.0.fdiv(2), 5.quo(2)] # => [2, 2.5, Rational(5,2)]
Integer division by zero causes a ZeroDivisionError
to be thrown. Floating-point division by zero does not
cause an error; it simply returns the value Infinity
. The case of 0.0/0.0
is special; on
most modern hardware, and with most operating systems, it evaluates to
another special floating-point
value known as NaN, or Not-a-Number.
The modulo (%
) operator
(and the synonymous modulo
method) compute the remainder after integer division. They can also be used
with Float
and Rational
operands. The divmod
method returns both quotient and
modulo :
x = 5%2 # => 1: quotient is 2, with 1 left over q,r = 10.divmod 3 # => [3,1]: quotient is 3, remainder is 1
Ruby uses the **
operator
for exponentiation. Exponents need not be
integers:
x**4 # This is the same thing as x*x*x*x x**-1 # The same thing as 1/x x**(1/3.0) # The cube root of x. Use Math.cbrt in Ruby 1.9 x**(1/4) # Oops! Integer division means this is x**0, which is always 1 x**(1.0/4.0) # This is the fourth-root of x
When multiple exponentiations are combined into a single
expression, they are evaluated from right to left. Thus, 4**3**2
is the same as 4**9
, not 64**2
.
Exponentiation can result in very large values. Remember that
integers can become arbitrarily large, but Float
objects cannot represent numbers
larger than Float::MAX
. Thus, the expression
10**1000
yields an exact integer
result, but the expression
9.9**1000
overflows to the Float
value Infinity
.
Fixnum
and Bignum
values support the standard bit-manipulation operators—~
, &
,
|
, ^
, >>
, and <<
—that are common in C, Java, and
many other languages. (See Operators for details.)
In addition, integer values can also be indexed like arrays to query
(but not set) individual bits.
The index 0 returns the least significant bit:
even = (x[0] == 0) # A number is even if the least-significant bit is 0
Most computer hardware and most computer languages (including Ruby)
approximate real numbers using a floating-point representation
like Ruby’s Float
class.
For hardware efficiency, most floating-point representations are
binary representations, which can exactly represent fractions like
1/2
, 1/4
, and 1/1024
. Unfortunately, the fractions we use
most commonly (especially when performing financial calculations) are
1/10
, 1/100
, 1/1000
, and so on. Binary floating-point
representations cannot exactly represent numbers as simple as 0.1
.
Float
objects have plenty of
precision and can approximate 0.1
very well, but the fact that this number cannot be represented exactly
leads to problems. Consider the following simple Ruby expression:
0.4 - 0.3 == 0.1 # Evaluates to false in most implementations
Because of rounding error, the difference between the
approximations of 0.4
and 0.3
is not quite the same as the
approximation of 0.1
. This problem
is not specific to Ruby: C, Java, JavaScript, and all languages that
use IEEE-754 floating-point numbers suffer from it as well.
One solution to this problem is to use a decimal representation
of real numbers rather than a binary representation. The BigDecimal
class from Ruby’s standard
library is one such representation. Arithmetic on BigDecimal
objects is many times slower than
arithmetic on Float
values. It is
fast enough for typical financial calculations, but not for scientific
number crunching. Decimal Arithmetic includes a short
example of the use of the BigDecimal
library.
18.191.233.205