The top hierarchy Number
class shows most of the behaviors
inherited by the subclasses as Float
, Integer
and
Fraction
. The Smalltalk way to learn about a behavior is to
point the System Browser toward a top hierarchy class and explore
the method categories.
Let’s suppose we want to round a float number. In Number
, we
explore the Truncation and round off method category to
discover several behaviors. The next thing to do is to test these
messages in a Workspace to discover the one we are searching for:
1.264 roundTo: 0.1 ⇒ 1.3 1.264 roundTo: 0.01 ⇒ 1.26 1.264 roundUpTo: 0.01 ⇒ 1.27 1.264 roundTo: 0.001 ⇒ 1.264
Number is a very strange place to look for an indexed loop in a given
interval. Nevertheless, an interval is defined by start and stop
numbers. In the Number
class, the method category
intervals reveals related behaviors. These methods work
polymorphically with most kinds of numbers:
1 to: 10 do: [:i | Transcript show: 1 / i; space] ⇒ 1 (1/2) (1/3) (1/4) (1/5) (1/6) (1/7) (1/8) (1/9) (1/10) 1 to: 10 by: 2 do: [:i | Transcript show: 1 / i; space] ⇒ 1 (1/3) (1/5) (1/7) (1/9) 1/10 to: 5/3 by: 1/2 do: [:i | Transcript show: i; space] ⇒ (1/10) (3/5) (11/10) (8/5) (1/10) (3/5) (11/10) (8/5) Float pi to: 5 by: 1/3 do: [:i | Transcript show: i; space] ⇒ 3.141592653589793 3.4749259869231266 3.80825932025646 4.141592653589793 4.474925986923126 4.808259320256459
Now, in the Integer
class, explore the method category
enumerating
, to find timesRepeat:
. When a
portion of code needs to be executed several times
15, without
the need for an index, the #timesRepeat:
message is sent to an
integer. We already saw this variant in a previous section of this
chapter. Throwing a 6-face die 5 times can be simulated with
an integer:
5 timesRepeat: [Transcript show: 6 atRandom; space] ⇒ 1 2 4 6 2
Note: Expect a different result each time.
Intervals of numbers can be defined on their own, for future use:
1 to: 10 ⇒ (1 to: 10) 1 to: 10 by: 2 ⇒ (1 to: 9 by: 2)
Intervals work with other kinds of objects such as Character
s:
$d to: $h ⇒ #($d $e $f $g $h)
In fact, an interval is an object of its own. It is a sort of collection:
(1 to: 10) class ⇒ Interval (1 to: 10 by: 2) squared ⇒ #(1 9 25 49 81) (1 to: 10) atRandom ⇒ 4 "different result each time"
In Spacewar!, when a ship is destroyed it is teleported to a random
position in the square gameplay area. Intervals are handy to pick
random coordinates. In the example below, the variable
randomCoordinate
holds a block of code – called an anonymous
function in other languages. It picks a random value in the
interval consisting of the gameplay area’s left and right extents:
randomCoordinate := [(area left to: area right) atRandom]. aShip velocity: 0 @ 0; morphPosition: randomCoordinate value @ randomCoordinate value
Compute the cosine values in the interval [0 ; 2PI], each 1/10. Output the result in the transcript.
Integer numbers are represented in different bases when prefixed with
the base and “r”. The r
stands for radix, the base root by
which the following number is interpreted.
When executing and printing Ctrl-p on such a
number, it is immediately printed in the decimal base:
2r1111 ⇒ 15 16rF ⇒ 15 8r17 ⇒ 15 20rF ⇒ 15 10r15 ⇒ 15
Writing numbers as Mayans or Babylonians16:
"The Babylonians" 60r10 ⇒ 60 60r30 ⇒ 180 60r60 ⇒ 360 60r30 + 60r60 ⇒ 540 (60r30 + 60r60) printStringRadix: 60 ⇒ '60r90' "The Mayans" 20r10 ⇒ 20 20r40 ⇒ 80 "pronounced 4-twenties in some languages" 20r100 ⇒ 400
Because of the nature of a number represented in base 2, shifting its bits left and right is equivalent to multiplying by 2 and dividing by 2:
(2r1111 << 1) printStringBase: 2 ⇒ '11110' 2r1111 << 1 ⇒ 30 (2r1111 >> 1) printStringBase: 2 ⇒ '111' 2r1111 >> 1 ⇒ 7
How would you multiply the integer 360 by 1024, without using the multiplication operation?
We saw decimal numbers are written with a dot “.” to separate the
integer and the decimal parts: 1.5
, 1235.021
or 0.5
. The number 0.0000241
is more easily
written with the scientific notation 2.41e-5
; it means 2
preceded by 5 zeros or 2 as the fifth digit after the decimal dot.
Computers encode and store decimal numbers imprecisely. You need to be aware of that when doing computation and equality comparisons. Many systems hide these errors because they are very tiny errors. Cuis-Smalltalk does not hide this inaccuracy. There is good information about this in the class comment of
Float
.
0.1 + 0.2 - 0.3 ⇒ 5.551115123125783e-17
In Example 3.11, the returned value should be zero but it is
not the case. The computer returns 5.55e-17
, or
0.0000000000000000555
, it is very close to zero, but there
is an error.
Give 3 calculations showing errors compared to the expected results.
When accuracy is mandatory use the Rational Numbers representation in Cuis-Smalltalk.
A rational number is written with the division symbol between two
integers: do Ctrl-p on 5/2
⇒
5/2
. Cuis-Smalltalk returns a rational number, it does not compute a
decimal.
What happens when executing this code
5/0
?
Let’s come back to our computer’s dyscalculia with decimal numbers. When using the rational numbers, the Example 3.11 becomes:
(1/10) + (2/10) - (3/10) ⇒ 0
This time we have the expected result. Under the covers, the computer only does the calculations with integer components so no roundoff results. This is a fine example where solving some problems requires a paradigm shift.
Return to Exercise 3.4 and use rational numbers to represent decimal numbers. The errors will be resolved.
Cuis-Smalltalk knows how to convert a decimal number to a fraction, by
sending the message #asFraction
. We already acknowledged the
computer’s dyscalculia with decimal numbers, this is why when
asking for a fraction representation we have this strange answer. The
internal computer representation of 1.3
is not exactly as
it seems:
(13/10) asFloat ⇒ 1.3 (13/10) asFloat asFraction ⇒ 5854679515581645/45035996273704
More strictly, to be repeated an integer number of times.
Base 20 and 60 number representations are not exclusive to these civilisations, although they are the most documented use cases.