The following code which attempts to convert a value well beyond the double precision range
StrToFloat('1e99999999')
correctly reports an incorrect floating point value in Delphi 10.2r3 with the Windows 32 bits compiler, but when compiled with the Window 64 bits compiler, it silently returns a 0 (zero).
Is there a way to have StrToFloat report an error when the floating point value is incorrect?
I have tried TArithmeticException.exOverflow, but this has no effect in that case.
I also tried TArithmeticException.exPrecision but it triggers in many usual approximation cases (f.i. it triggers when converting '1e9').
Issue was noticed with Delphi 10.2 update 3
addendum: to workaround the issue, I have started a clean-room alternative implementation of string to double conversion, initial version with tests can be found in dwscript commit 2ba1d4a
This is a defect that is present in all versions of Delphi that use the PUREPASCAL version of StrToFloat
. That maps through to InternalTextToExtended
which reads the exponent like this:
function ReadExponent: SmallInt;
var
LSign: SmallInt;
begin
LSign := ReadSign();
Result := 0;
while LCurrChar.IsDigit do
begin
Result := Result * 10;
Result := Result + Ord(LCurrChar) - Ord('0');
NextChar();
end;
if Result > CMaxExponent then
Result := CMaxExponent;
Result := Result * LSign;
end;
The problem is the location of
if Result > CMaxExponent then
This test is meant to be inside the loop, and in the asm x86 version of this code it is. As coded above, with the max exponent test outside the loop, the 16 bit signed integer result value is too small for your exponent of 99999999
. As the exponent is read, the value in Result
overflows, and becomes negative. So for your example it turns out that an exponent of -7937
is used rather than 99999999
. Naturally this leads to a value of zero.
This is a clear bug and I have submitted a bug report: RSP-20333.
As for how to get around the problem, I'm not aware of another function in the Delphi RTL that performs this task. So I think you will need to do one of the following:
StrToFloat
.StrToFloat
.Finally, I am grateful for you asking this question because I can see that my own program is affected by this defect and so I can now fix it!
Update:
You may also be interested to look at a related bug that I found when investigating: RSP-20334. It might surprise you to realise that, StrToFloat('߀')
, when using the PUREPASCAL version of StrToFloat
, returns 1936.0
. The trick is that the character that is being passed to StrToFloat
is a non-Latin digit, in this case U+07C0.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With