org.sonar.l10n.delphi.rules.community-delphi.MathFunctionSingleOverload.html Maven / Gradle / Ivy
Why is this an issue?
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
.
How to fix it
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;
Resources