8.2: Numbers
- Page ID
- 36373
\( \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}\)Remarkably, numbers in Smalltalk 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 Smalltalk class hierarchy.
Numbers are found in the Kernel-Numbers category. The abstract root of this hierarchy is Magnitude
, which represents all kinds of classes supporting comparision operators. Number
adds various arithmetic and other operators as mostly abstract methods. Float
and Fraction
represent, respectively, floating point numbers and fractional values. 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
. (Complex
numbers are not comparable, and so do not inherit from Number
.)
Methods < and = are abstract. The remaining operators are generically defined. For example:
Code \(\PageIndex{1}\) (Squeak): Abstract Comparison Methods
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, such as i
, which converts a Number
to an instance of Complex
with a zero real component, and others 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.
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 interesting, 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 Smalltalk:
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.
\(\bigstar\) 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.
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 3:
n := 2. 3 timesRepeat: [ n := n*n ]. n → 256