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:
- Roll your own
StrToFloat
.
- Pre-process the string, and handle out of range exponents before they read
StrToFloat
.
- Use one of the functions from the C runtime library that performs the same task.
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.