StrToFloat не сообщает недопустимые номера с плавающей запятой в Delphi 64bits
следующий код, который пытается преобразовать значение далеко за пределы диапазона двойной точности
StrToFloat('1e99999999')
правильно сообщает неверное значение с плавающей запятой в Delphi 10.2r3 с 32-битным компилятором Windows, но при компиляции с 64-битным компилятором Window он молча возвращает 0 (ноль).
есть ли способ сообщить StrToFloat об ошибке, когда значение с плавающей запятой неверно?
Я пробовал TArithmeticException.exOverflow, но это не имеет никакого эффекта в этом случае.
Я также попробовал TArithmeticException.exPrecision, но он срабатывает во многих обычных случаях приближения (f.Я. он запускается при преобразовании '1e9').
проблема была замечена с Delphi 10.2 update 3
дополнение: чтобы обойти проблему, я начал альтернативную реализацию чистой комнаты строки для двойного преобразования, начальную версию с тестами можно найти в фиксация dwscript 2ba1d4a
1 ответов
это дефект, который присутствует во всех версиях Delphi, которые используют PUREPASCAL версию StrToFloat
. Это карта до InternalTextToExtended
который читает показатель следующим образом:
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;
проблема заключается в местоположении
if Result > CMaxExponent then
этот тест должен быть внутри цикла, и в asm x86-версия этого кода. Как указано выше, при тесте max exponent вне цикла 16-битное целое число со знаком слишком мало для вашего показателя 99999999
. По мере чтения экспоненты значение в Result
переполняется, и становится отрицательным. Итак, для вашего примера получается, что показатель -7937
используется вместо 99999999
. Естественно, это приводит к нулевому значению.
это явная ошибка и я подала отчет об ошибке: RSP-20333.
что касается того, как обойти проблему, я не знаю другой функции в Delphi RTL, которая выполняет эту задачу. Поэтому я думаю, что вам нужно будет сделать один из следующее:
- свернуть свой собственный
StrToFloat
. - предварительно обработайте строку и обработайте показатели вне диапазона, прежде чем они прочитают
StrToFloat
. - используйте одну из функций из библиотеки времени выполнения C, которая выполняет ту же задачу.
наконец, я благодарен за то, что вы задаете этот вопрос, потому что я вижу, что моя собственная программа затронута этим дефектом, и поэтому теперь я могу исправить это!
обновление:
Вам также может быть интересно посмотреть на связанную ошибку, которую я нашел при расследовании:RSP-20334. Возможно, вы удивитесь, осознав это,StrToFloat('')
, при использовании PUREPASCAL версии StrToFloat
возвращает 1936.0
. Фокус в том, что символ, который передается StrToFloat
- нелатинская цифра, в этом случае U + 07C0.