[prev] [up] [next]

Number classes

The number hierarchy provides a common protocol for many numeric types. Smalltalk automatically converts between internal representations and provides unlimited precision integer arithmetic.

The most useful numeric classes are:

Use the systemBrowser to have a more detailed look into the implementation.

Number

Number is the abstract superclass of all number-like objects. It provides methods which are independent of the actual numeric representation.

Smalltalk's numeric classes make good use of polymorphism in the language: instances of all numeric classes may be used interchangable in most operations (for some, such as bit operations, it does not make sense).
Also, results of arithmetic (and other) operations are converted as appropriate.
For example, executing:

	1 / 3
(send the message 'divide by 3' to the integer '1') will return a fractional result, represented by an instance of Fraction.

Protocol common to all numbers is:

THe above is only an excerpt of the whole protocol - use the browser to see more.

More details are found in the "Number class documentation".

Integer

Integer is the abstract superclass of all integral number objects. There are no instances of Integer itself, but instead of one of its subclasses, SmallInteger or LargeInteger. Conversion between smallIntegers and largeIntegers is transparent; if some value cannot be represented as smallInteger, the system automatically creates a largeInteger object for it.

In addition to the above listed generic protocol for all numbers, integers respond to a number of additional messages for bitwise access, factorial and fibonacci computations, hex digit extraction etc.

More details are found in "Integer's class documentation", in "SmallInteger's class documentation" and in "LargeInteger's class documentation".

Fraction

Fractions are rational numbers, typically resulting from a division of two integers which does not give an integral result. In contrast to floatingPoint arithmetic, fractional arithmetic is exact. Therefore:
    (1 / 3) * 3 = 1
while the corresponding float operation:
    (1 / 33) asFloat * 33
may return 0.999999... on some systems due to rounding errors.

Fractional results from arithmetic operations are automatically reduced; therefore,

    (1 / 3) * (1 / 3) * 3
gives a result of 1/3 (not 3/9).

Beside memory limitations, the precision of fractional numbers is unlimited. A fractional resulting from an arithmetic operation is always reduced by finding the greatest common divisor of the numerator and denominator. Therefore, you will never get a fractional result like "(2 / 6)".

More details are found in the "Fraction class documentation".

FixedPoint - Decimal Numbers

FixedPoint numbers are fractions with a denominator being a power of 10 (i.e. 10, 100, 1000 etc.). Like with fractions, fixedPoint arithmetic is exact. In addition, fixedPoint numbers have an instance-specific precision specified, which defines how many post-decimal-point digits are shown in the printed representation. When printed, the output is rounded to that number of post-decimal-point digits (however, internally the exact value is kept and used for arithmetic).

FixedPoint numbers are the right choice if you have to deal with money and other entities where rounding errors are to be avoided.

As a special form of fraction, fixedpoint numbers respond to the usual arithmetic protocol. Any other number can be converted to a fixedpoint via:

More details are found in the "FixedPoint class documentation".

Float

Floats are limited precision real numbers. The representation depends on the underlying machine's and the C-compiler's double implementation.
On most modern systems, the IEEC representation is used (but be careful on OpenVMS and IBM mainframe systems...).

Typically, floats are represented in 64bits and the precision of the mantissa is 53bits (i.e. some 15 decimal digits) - but you should not depend on this being true on all hardware architectures. Consult your CPU and/or C-compiler's documentation of your actual system for more information.
Two companion classes called ShortFloat and LongFloat are also available, which correspond to the C-compiler's float and long double implementations. Typically ShortFloat uses a 32 bit representation (i.e. roughly 6 decimal digits), while LongFloat uses an 80bit or 128 bit representation (i.e. roughly 19 digits).
Be aware, that not all C-compilers support the long double type; on those systems, LongFloats are mapped to regular doubles with 64 bits.

Due to historic reasons, the existing Smalltalk systems used different precision and/or names for their float number classes:

For portability, ST/X's "Float" class uses double (64bit) precision, and ST/X defines "Double" as an alias for it. Thus both "Double" and "Float" refer to the same 64bit floating point class. If you explicitly want only 32bit of precision, you have to use instances of "ShortFloat".

Since having more precision does usually no harm to the program, this choice should ease porting of Smalltalk code from any system. However, be aware of the fact that a float in ST/X takes up more memory than a float in ST-80 (which should not be a problem, these days). Late news:
Abiously, the ANSI standardization team also recgnized those difficulties and defined aliases for those 3 classes: "FloatE", "FloatD" and "FloatQ" are alieases to the single precision, double precision and long precision float classes respectively.

Thus, if you have to ensure a particular precision, either refer to one those classes explicitly, or convert your numbers using one of: "asFloatE", "asFloatD" or "asFloatQ".

A warning:
many beginners (and as real world examples show) also some non-beginners seem to forget that floating point numbers are only approximations to a real number, and suffer from errors due to non-representability and from rounding.

These errors are not due to impementation reasons; they are inherent in the way floating point numbers are represented, and exist in all languages and all machines. The error may be made arbitraryly small, by increasing the precision, but will never disappear completely.

For these reasons:
Never use floats when exact results are needed - especially when computing monetary values!

More details are found in "Float's class documentation" , "ShortFloat's class documentation". and in "LongFloat's class documentation".

you may also take a look at the experimental "QDouble". class, which provides roughly four times the precision, but being much slower in computations.

All of these classes inherit from "LimitedPrecisionReal".

Others

There are a number of other Numeric classes, for example to implement infinity or complex numbers. Use a systemBrowser on the Number-class hierarchy to find out more.

You can also extent the Number hierarchy, by adding new classes which implement a certain minimum protocol (they should know how to perform some of the basic arithmetic operations, and how to be converted into other representations).
As an example and guideline on how this is done, have a look at the implementation of the Complex number class.

Notes:

(*)
One bit is lost for implementation reasons. Therefore, the number of bits in a smallInteger is the machine's native integer size minus one; usually 31 (63 on a 64bit architecture like the DEC-alpha or x86_64).
( for details, see object representation)

Copyright 1996 Claus Gittinger Development & Consulting

<info@exept.de>

Doc $Revision: 1.33 $ $Date: 2017/06/22 14:53:04 $