This chapter describes GemStone’s numeric classes. These include Integers, floating point (limited-precision rational numbers), fractions (arbitrary precision rational numbers), and decimal numbers.
Most numbers can be specified as literals within your code, and most numbers can be used in expressions with, or converted to, other types of numbers.
Integers
Describes classes that represent whole numbers: SmallInteger and LargeInteger.
Binary Floating Point
Describes classes for binary floating point numbers: SmallDouble and Float.
Other Rational Numbers
Describes classes for other rational numbers with different ranges and precisions, including Fraction, FixedPoint, ScaledDecimal, and DecimalFloat.
Internationalizing Decimal Points using Locale
How to control the display of decimal points.
Random Number Generator
Information on the set of random number generator classes, providing random numbers of various purposes.
Integers in GemStone are composed of SmallIntegers and LargeIntegers. Most Integers you are likely to use will be SmallIntegers, in the range of -260 to 260 -1. Integers outside this range are represented by LargeIntegers. Operations that result in a value outside the SmallInteger range transparently result in LargeIntegers, and vice-versa
The literal syntax for Integer will create either a SmallInteger or LargeInteger.
SmallIntegers are special (immediate) objects, that is, the number itself is encoded in the OOP, making instances of this class both small (since no further storage is required) and fast. They are also unique, so SmallIntegers of the same value are always identical (==) as well as equal (=).
SmallIntegers have a range from -260 to 260 -1. Values outside this range must be represented as LargeIntegers.
LargeIntegers are not special objects; they require an OOP.
Each instance of LargeInteger is stored as an array of bytes, where every 4 bytes represents a base 4294967296 digit. The first 4 bytes are the sign digit (0 or 1), the next 4 bytes in that array constitute the least significant base 4294967296 digit, and the last 4 bytes are the most significant base 4294967296 digit.
Instances of LargeInteger have a maximum size of 4067 digits plus the sign. The maximum absolute value for a LargeInteger is (2130144 - 1). Attempting to create a LargeInteger that exceeds this maximum will fail with an Integer overflow error.
Floating point values in GemStone are composed of SmallDoubles and Floats. The most commonly used floating points will be SmallDoubles. While both SmallDouble and Float represents 8-byte binary floating point numbers, as defined in IEEE standard 754, SmallDoubles have a reduced exponent range. Some floating point values therefore can only be represented by instances of Float, rather than SmallDouble. Similarly to SmallInteger and LargeInteger, GemStone operations return one or the other as needed.
The numerical behavior of instances of Float is implemented by the mathematics package of the vendor of the machine on which the Gem process is running. There are slight variations in results with different platform’s implementation of the
IEEE-754 standard.
You can get the components of a floating point value using the methods signBit,
exponent, and mantissa.
SmallDoubles are special objects; as with SmallIntegers, the number itself is encoded in the OOP, making instances small and fast. They are also unique, so SmallDoubles of the same value are identical (==) as well as equal (=).
Each SmallDouble contains a 61 bit value, in IEEE format but with reduced exponent range. There is 1 sign bit, 8 bits of exponent and 52 bits of fraction. SmallDoubles are always in big-endian format (both on disk and in memory).
SmallDoubles can represent C doubles that have value zero or that have exponent bits in range 0x381 to 0x3ff, which corresponds to about 5.0E-39 to 6.0E38; approximately the range of C 4-byte floats.
Floats are not special objects; they require an OOP.
Each Float contains a 64 bit value in IEEE format, with 1 sign bit, 11 bits of exponent and 52 bits of mantissa. Floats are in cpu-native byte order when in memory, and the byte order of the extent when on disk.
In addition to the finite numbers, the IEEE standard defines floating point formats to include Infinity (positive and negative) and NaNs (not a Number), which can be quiet or signaling. NaNs results from an operations whose result is not a real number, such as:
-23 sqrt
%
PlusQuietNaN
Infinity results from operations that return a value outside the range of representation, such as:
32.0 / 0
%
PlusInfinity
ExceptionalFloats are named, unique instances of Float, not of SmallDouble. Exceptional Floats include:
PlusInfinity
MinusInfinity
PlusQuietNaN
MinusQuietNaN
PlusSignalingNaN
MinusSignalingNaN
Since the sign of NaNs is not defined, GemStone operations return only positive NaNs; they do not return MinusQuietNan or MinusSignalingNan.
An unusual quality of NaNs is that they are not equal to themselves. This means that NaNs can cause problems if used as keys of hashed equality-based collections.
PlusQuietNaN = PlusQuietNaN
%
false
Literal numbers in evaluated code that include a decimal point by default create a SmallDouble or Float. If the value is in the SmallDouble range, a SmallDouble will be created, otherwise a Float will be created.
Literal floats may be specified using exponential notation. For example, 5.1E3 and 5.1E-3 are valid SmallDouble literals.
Note that using a plus sign before the exponent is not allowed in literal floats, although it can be used to create floating points from strings (using Float fromString:). This avoids ambiguity with Smalltalk dialects that would interpret this as the addition operator. For example, 5.1E+3, which historically GemStone would interpret as the same as 5.1E3, is disallowed; code must either omit the +, or include white space to clarify the addition operator.
SmallDoubles and Floats are printed by default, using asString, in exponential notation. For readability, you can format floating point numbers for printing with asStringUsingFormat:.
This method accepts an Array of three elements:
12.3456 asStringUsingFormat: #(-8 2 false)
' 12.35'
12.3456 asStringUsingFormat: #(4 10 true)
'1.2345600000E01'
By default, Float and SmallDouble are printed with the equivalent of #(1 16 true).
For some application, binary floating points are problematic, since there are common decimal values that cannot be expressed exactly in binary floating point; for example, 5.1 does not have a precise binary floating point representation.
5.1
%
5.0999999999999996E00
There are several options to avoid this: Fraction, FixedPoint, ScaledDecimal, and DecimalFloat. These classes are independent of each other, and each provides different qualities of precision and range.
Fractions precisely represent rational numbers. Fractions are composed of an integer numerator and an integer denominator. As the ratio of two Integers, Fractions can represent any rational number to an unbounded level of precision.
The display of fractions is as the numerator and denominator separated by the $/ character, which is also the division binary method. Fractions have no literal representation. An expression such as 1/3, which performs a division of two Integers, will return a Fraction if the result is not an Integer.
(1/3) printString
%
1/3
Any expression, not just division expressions, that could result in Fractions will be reduced automatically, to the lowest Fraction or to an Integer.
(5/6) + (1/6)
%
1
FixedPoints, like Fractions, represents rational numbers, but also include information on how they should be displayed. A FixedPoint is composed of an integer numerator, integer denominator, and an integer scale. Like Fraction, this allows rational numbers to be represented with unbounded precision, and since fractional arithmetic is used in calculations, numerical results do not lose precision.
The scale provides automatic rounding when representing the FixedPoint as a String.
ScaledDecimals represent a decimal number to the precision of a fixed number of fractional digits. ScaledDecimals are composed of an integer mantissa and a power-of-10 scale. While ScaledDecimals represent decimal fractions to the precision specified, not all values can be represented exactly by ScaledDecimals. The maximum scale is 30000.
ScaledDecimals use a literal notation using s, such as 1.23s2.
ANSI does not precisely specify the scale of a ScaledDecimal that is returned by mathematical operations. The following rules are used:
For some mathematical operations, the returned value type is a ScaledDecimal, but the returned value cannot always be exactly represented as a ScaledDecimal with the correct scale. In these cases, the results are rounded using the following rules:
DecimalFloats represent base 10 floating point numbers, as defined in IEEE standard 854-1987.
Objects of class DecimalFloat have 20 digits of precision, with an exponent in the range -15000 to +15000. The first byte has encoded in it the sign and kind of the floating-point number. Bit 0 is the sign bit (0=positive, 1=negative). The values in bits 1 through 3 indicate the kind of DecimalFloat:
001x = normal
010x = subnormal
011x = infinity
100x = zero
101x = quiet NaN
110x = signaling NaN
Bytes 2 and 3 encode the exponent as a biased 16-bit number (byte 2 is more significant). The actual exponent is calculated by subtracting 15000. Bytes 4 through 13 form the mantissa of the number. Each byte holds two BCD digits, with bits 4 through 7 of byte 4 containing the most significant digit.
Similarly to Float, operations that would not result in a real number, or that produce a result outside the representable range, result in Exceptional numbers:
DecimalPlusInfinity
DecimalMinusInfinity
DecimalPlusQuietNaN
DecimalMinusQuietNaN
DecimalPlusSignalingNaN
DecimalMinusSignalingNaN
The class Locale allows you to obtain operating system locale information and use or override it in GemStone. GemStone currently only uses the decimalPoint setting, to provide localized reading and writing of numbers involving decimal points. Updates to Locale are stored in session state, and only persist for the lifetime of the session. They are not affected by commit or abort.
Note that Smalltalk syntax requires the use of “.” as the decimal point separator, so expressions involving literal floating point numbers within Smalltalk code will still require use of the period, regardless of Locale.
To override the operating system locale information, use the following message:
Locale class >> setCategory: categorySymbol locale: LocaleString
The LocaleString passed to setCategory:locale: must be defined on the host machine. You can use the UNIX command locale -a to get a list of all available LocaleStrings.
While there are a number of Locale category symbols, the only ones that are of use in this release are #LC_NUMERIC and #LC_ALL, either of which will set the category that affects the decimal point.
For example, To use decimal localization appropriate for Germany:
Locale setCategory: #LC_NUMERIC locale: 'de_DE'.
To reset to UNIX default value, using period:
Locale setCategory: #LC_ALL locale: 'C'.
The following method returns the decimalPoint setting for the current Locale:
Locale decimalPoint
Regardless of Locale, you can read a string with a period decimal point using the methods:
Float class >> fromStringLocaleC:
DecimalFloat class >> fromStringLocaleC:
The class Random and its subclasses provide random number generation.
There are two types of random number generation, which correspond to separate subclass hierarchies. The SeededRandom subclasses provide random numbers generated within GemStone code, using a starting seed value. The HostRandom subclass provides access to the host operating system’s /dev/urandom random number generator. This is much slower, but unlike the SeededRandom numbers, on some platforms this may be designed to be cryptographically secure.
The class hierarchy of the Random classes are:
Object
Random (abstract)
HostRandom
SeededRandom (abstract)
Lag1MwcRandom
Lag25000CmwcRandom
The Random class is an abstract superclass for the random number generators. It also can be used to create an instance of the default random number generator class, Lag25000CmwcRandom. Sending instance creation messages to Random will return instances of Lag25000CmwcRandom. For example:
Random seed: 12345
%
aLag25000CmwcRandom
Random new
will create an instance of Lag25000CmwcRandom that is seeded with numbers generated from the host OS /dev/urandom.
Once you have an instance of a concrete subclass of Random, you can generate random numbers or collections of random numbers with the following range and type specifications:
float - a random Float in the range [0,1)
floats: n - a collection of n random floats in the range [0,1)
integer - a random non-negative 32-bit integer, in the range [0,232-1]
integers: n - a collection of n random non-negative integers in the range [0,232-1]
integerBetween: l and: h - a random integer in the range [l,h]. l and h should be less than approximately 231.
integers: n between: l and: h - a collection of n random integers in the range [l,h]. l and h should be less than approximately 231.
smallInteger - Answer a random integer in the SmallInteger range,
[-260,260-1]
Subsequent calls to the same instance will generate new random numbers.
You should create an instance of a Random subclass and retain that to generate many random numbers, rather than creating new instances of a Random subclass.
HostRandom allows access to the host operating system's /dev/urandom random number generator.
HostRandom is much slower than the other subclasses of Random. However, /dev/urandom on some platforms may be intended to be cryptographically secure random number generator, which none of the other subclasses are. It also has the advantage of not needing an initial seed, and so is good for generating random seeds for the faster Random subclasses.
HostRandom uses a shared singleton instance, which is accessed by sending #new to the class HostRandom. Sending #new has the side effect of opening the underlying file /dev/urandom. This file normally remains open for the life of the session, but if you wish to close it you can send #close to the instance, and later send #open to reopen it. If you store a persistent reference to the singleton instance the underlying file will not be open in a new session and you must send #open to the instance before asking for a random number.
Since HostRandom is a service from the operating system, it cannot be seeded, and should not be used when a repeatable random sequence of numbers is needed.
SeededRandom is an abstract superclass for classes that generate sequences of random numbers that can be generated repeatedly by giving the same initial seed to the generator.
In addition to creating new instances using the class methods new and seed:, the following instance methods allow repeatable sequences to be generated:
seed: aSmallInteger
Sets the seed of the receiver from the given seed, which can be any SmallInteger. The subsequent random number sequence generated will be the same as if this generator had been created with this seed.
fullState, fullState: stateArray
The internal state of a generator is more than can be represented by a single SmallInteger. These messages allow you to retrieve the full state of a generator at any time, and to restore that state later. The random number sequence generated after the restoration of the state will be the same as that generated after the retrieval of the state. You might, for instance, allow a generator to get its initial state from /dev/urandom, then save this state so the random sequence can be repeated later.
Lag1MwcRandom is intended for internal use only, in creating a random seed for instances of Lag25000CmwcRandom. Lag1MwcRandom is slower, is not perfectly fair, and has a shorter period, so the only advantage is its ability to be seeded by a single 61-bit SmallInteger, rather than a seed of more than 800000 bits as required by Lag25000CmwcRandom.
Lag25000CmwcRandom is a seedable random generator with a period of over 10240833. It is a lag-25000 generator using the complementary multiply-with-carry algorithm to generate random numbers. Its period is so long that every possible sequence of 24994 successive 32-bit integers appears somewhere in its output, making it suitable for generating random n-tuples where n<24994. Its output is fair in that the number of 0 bits and 1 bits in the full sequence are equal.
While this generator is recommended for most uses, it is not cryptographically secure, so for applications such as key generation you should consider using HostRandom, once you satisfy yourself that HostRandom is secure enough on your operating system.
You can also allow the seed bits to be initialized from the HostRandom, then retrieve that state by sending #fullState. That state can later be restored by sending the retrieved state as an argument to #fullState:.