10.2: Numbers
- Page ID
- 39627
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)
Numbers in Pharo are not primitive data values but true objects. Of course numbers are implemented efficiently in the virtual machine, but the Number
hierarchy is as perfectly accessible and extensible as any other portion of the class hierarchy.
The abstract root of this hierarchy is Magnitude
, which represents all kinds of classes supporting comparison operators. Number
adds various arithmetic and other operators as mostly abstract methods. Float
and Fraction
represent, respectively, floating point numbers and fractional values. Float subclasses (BoxedFloat64
and SmallFloat64
) represent Float on certain architectures. For example BoxedFloat64
is only available for 64 bit systems. Integer
is also abstract, thus distinguishing between subclasses SmallInteger
, LargePositiveInteger
and LargeNegativeInteger
. For the most part, users do not need to be aware of the difference between the three Integer
classes, as values are automatically converted as needed.
Magnitude
Magnitude
is the parent not only of the Number
classes, but also of other classes supporting comparison operations, such as Character
, Duration
and Timespan
.
Methods < and = are abstract. The remaining operators are generically defined. For example:
Magnitude >> < aMagnitude "Answer whether the receiver is less than the argument." ^ self subclassResponsibility Magnitude >> > aMagnitude "Answer whether the receiver is greater than the argument." ^ aMagnitude < self
Number
Similarly, Number
defines +
, -
, *
and /
to be abstract, but all other arithmetic operators are generically defined.
All Number
objects support various converting operators, such as asFloat
and asInteger
. There are also numerous shortcut constructor methods which generate Durations
, such as hour
, day
and week
.
Numbers
directly support common math functions such as sin
, log
, raiseTo:
, squared
, sqrt
and so on.
The method Number>>printOn:
is implemented in terms of the abstract method Number>>printOn:base:
. (The default base is 10.)
Testing methods include even
, odd
, positive
and negative
. Unsurprisingly Number
overrides isNumber
. More interestingly, isInfinite
is defined to return false
.
Truncation methods include floor
, ceiling
, integerPart
, fractionPart
and so on.
1 + 2.5 >>> 3.5 "Addition of two numbers"
3.4 * 5 >>> 17.0 "Multiplication of two numbers"
8/2 >>> 4 "Division of two numbers"
10 - 8.3 >>> 1.7 "Subtraction of two numbers"
12 = 11 >>> false "Equality between two numbers"
12 ~= 11 >>> true "Test if two numbers are different"
12 > 9 >>> true "Greater than"
12 >= 10 >>> true "Greater or equal than"
12 < 10 >>> false "Smaller than"
100@10 >>> 100@10 "Point creation"
The following example works surprisingly well in Pharo:
1000 factorial / 999 factorial >>> 1000
Note that 1000 factorial
is really calculated, which in many other languages can be quite difficult to compute. This is an excellent example of automatic coercion and exact handling of a number.
To do. Try to display the result of
1000 factorial
. It takes more time to display it than to calculate it!
Float
Float
implements the abstract Number
methods for floating point numbers. More interestingly, Float
class (i.e., the class-side of Float
) provides methods to return the following constants: e
, infinity
, nan
and pi
.
Float pi >>> 3.141592653589793
Float infinity >>> Infinity
Float infinity isInfinite >>> true
Fraction
Fractions are represented by instance variables for the numerator and denominator, which should be Integers
. Fractions
are normally created by Integer
division (rather than using the constructor method Fraction>>numerator:denominator:
):
6/8 >>> (3/4)
(6/8) class >>> Fraction
Multiplying a Fraction
by an Integer
or another Fraction
may yield an Integer
:
6/8 * 4 >>> 3
Integer
Integer
is the abstract parent of three concrete integer implementations. In addition to providing concrete implementations of many abstract Number
methods, it also adds a few methods specific to integers, such as factorial
, atRandom
, isPrime
, gcd:
and many others.
SmallInteger
is special in that its instances are represented compactly — instead of being stored as a reference, a SmallInteger
is represented directly using the bits that would otherwise be used to hold a reference. The first bit of an object reference indicates whether the object is a SmallInteger
or not. Now the virtual machine abstracts that from you, therefore you cannot see this directly when inspecting the object.
The class methods minVal
and maxVal
tell us the range of a SmallInteger
:
SmallInteger maxVal = ((2 raisedTo: 30) - 1) >>> true
SmallInteger minVal = (2 raisedTo: 30) negated >>> true
When a SmallInteger
goes out of this range, it is automatically converted to a LargePositiveInteger
or a LargeNegativeInteger
, as needed:
(SmallInteger maxVal + 1) class >>> LargePositiveInteger
(SmallInteger minVal - 1) class >>> LargeNegativeInteger
Large integers are similarly converted back to small integers when appropriate.
As in most programming languages, integers can be useful for specifying iterative behaviour. There is a dedicated method timesRepeat:
for evaluating a block repeatedly. We have already seen a similar example in Chapter : Syntax in a Nutshell.
|n| n := 2. 3 timesRepeat: [ n := n * n ]. n >>> 256