High-precision overloads (Double and Extended) of the standard math
functions are preferred over the single-precision (Single) overloads, for stability
and platform independent behaviour.
Firstly, single-precision numbers are only fully accurate for a relatively small range of numbers.
Routines that produce very small or very large numbers may be very inaccurate when using
Single - for example, integers larger than 16777216 cannot be
stored accurately.
Secondly, the single-precision overloads can return extended-precision values on 32-bit Windows in some cases.
Delphi carries out single-precision floating point calculations using extended-precision values.
In 64-bit, the standard math functions invariably truncate their result to single-precision as
expected.
In 32-bit, however, the standard math functions do not truncate their result to single-precision.
This means that on 32-bit Windows, these functions unexpectedly return an Extended
instead of a Single.
For example, the following code will print 1,000,000,000,000 on 32-bit and 999,999,995,904 on 64-bit:
procedure Example; var MyNum: Double; begin MyNum := Power(10, 12); // Uses Single overload, which claims to return Single Writeln(MyNum); end;
The following code will print 1,000,000,000,000 on both 32-bit and 64-bit:
procedure Example; var MyNum: Double; begin MyNum := Power(Double(10), 12); // Uses Double overload, which claims to return Double Writeln(MyNum); end;
Note that in Delphi, the type of a number literal is the smallest possible type that can hold that
value. This means that integer and floating point literals are usually interpreted as a
Single.
If possible, refactor your code to use the Double or Extended overloads:
procedure Example(MyNum: Single); begin Power(MyNum, 2); end;
procedure Example(MyNum: Double); begin Power(MyNum, 2); end;
Otherwise, cast the number to Double or Extended before invocation:
procedure Example(MyNum: Integer); begin Power(MyNum, 2); end;
procedure Example(MyNum: Integer); begin Power(Double(MyNum), 2); end;