2015-09-20 2 views
2

Я пытаюсь преобразовать расширенное значение с большим показателем в Delphi 7 на Win 7-64, и я получаю исключение «Неверная операция с плавающей запятой» на то, что, по моему мнению, является допустимым значением , Значение равно 3.6854775808e-4912, которое отладчик сообщает без проблем.Ошибка преобразования строки с расширением расширенной строки Delphi

Следующие процедуры были опробованы и все они генерируют это исключение:

FloatToStr. Формат. ФорматFloat. FloatToText.

Кто-нибудь знает, что происходит?

EDIT:

я, вероятно, следовало бы отметить, что я ищу буфер для конкретного расширенного значения и местоположения могут быть любого смещения в буфере. Метод копирует 10 байтов в запись варианта и извлекает увеличенное значение из записи. Затем делается попытка преобразовать расширенное значение в строку, используя одну из описанных выше подпрограмм, которая генерирует ошибку. Я также обнаружил, что попытка умножить значение на 1.0 также порождает ошибку.

TDecoderRec = record 
    case integer of 
    0 : (Binary: TBinaryArray); 
    1 : (Character : TCharArray); 
    2 : (ShortIntVal: ShortInt); 
    3 : (ByteVal: Byte); 
    4 : (SmallIntVal: SmallInt); 
    5 : (WordVal: Word); 
    6 : (IntegerVal: Integer); 
    7 : (LongWordVal: LongWord); 
    8 : (Int64Val: Int64); 
    9 : (SingleVal: Single); 
    10 : (Real48Val: Real48); 
    11 : (RealVal: Real); 
    12 : (DoubleVal: Double); 
    13 : (CompVal: Comp); 
    14 : (CurrencyVal: Currency); 
    15 : (ExtendedVal: Extended); 
end; { TDecoderRec } 

fldExtended.AsExtended:= DecoderRec.ExtendedVal; 

procedure TCustomNumericEdit.SetAsExtended(Value: Extended); 
begin 
    AssignText(FloatToStr(Value)); { <<---- FloatToStr causes the error } 
end; { TCustomNumericEdit.SetAsExtended } 

Эти шестигранный байт, содержащие ExtendedVal:

74 02 08 03 54 6F 70 03 A4 00 

Это значение, что отчеты отладчика:

3.6854775808e-4882 

program ProjectFloatError; 

{$APPTYPE CONSOLE} 

uses 
    System.SysUtils; 
var 
    Value : Extended; 
    s  : String; 
begin 
    try 
    Value.Bytes[0] := $74; 
    Value.Bytes[1] := $02; 
    Value.Bytes[2] := $08; 
    Value.Bytes[3] := $03; 
    Value.Bytes[4] := $54; 
    Value.Bytes[5] := $6F; 
    Value.Bytes[6] := $70; 
    Value.Bytes[7] := $03; 
    Value.Bytes[8] := $A4; 
    Value.Bytes[9] := $00; 
    s := FloatToStr(Value); // <-- Invalid floating point operation 
    WriteLn(s); 
    ReadLn; 
    except 
    on E: Exception do 
    begin 
     Writeln(E.ClassName, ': ', E.Message); 
     ReadLn; 
    end; 
    end; 
end. 
+0

Все должно работать. Мы не видим ваш код. –

+0

@DelphiFan: Происходит ли ошибка при преобразовании из 'Extended' в' String' или от 'String' до' Extended'? Если вы начинаете с 'Extended', для любой из этих функций не имеет смысла сбой при создании' String', так как у вас уже есть 'Extended' в памяти. Но преобразование 'StrToFloat()', конечно, может завершиться ошибкой, если представленное значение слишком велико, чтобы вписаться в 'Extended'. Как сказал Дэвид, пожалуйста, покажите фактический код, который терпит неудачу. –

+0

@ Дэвид и Реми: Я должен был быть более ясным, сожалею об этом. Похоже, что поле ExtendedVal записи действительно возвращает недопустимую комбинацию байтов. Странно то, что отладчик не имеет проблем с ним и отображает значение, которое находится в допустимом диапазоне. – DelphiFan

ответ

0

Любая операция выполнение ed на это значение приводит к исключению с плавающей запятой, что указывает на то, что это значение не является допустимым значением с плавающей запятой.

Предполагая, что значение, которое вы ищете, является допустимым и единственная проблема заключается в переводе этой последовательности байтов в представление в переменной с плавающей запятой, то если вы ищете буфер записи для этой конкретной последовательности байтов зачем вам вообще конвертировать в плавающую точку?

Вы, по-видимому, знаете строковое представление последовательности байтов, если вы в состоянии искать эту последовательность байтов, поэтому я не понимаю, почему существует необходимость в преобразовании времени выполнения из известной последовательности байтов в известную строковое представление.

Который затем задает вопрос, если эта последовательность байтов не является допустимым значением Extended, то оказывается, что вся основа для того, что вы пытаетесь достичь, является ошибочной и нуждается в дальнейшем рассмотрении?

+0

Какое значение вы получаете, когда вы меняете байты. Возможно, апеллятору не удалось конвертировать из сети в хост-порядок. –

+0

@David: изменение порядка в буфере и назначение расширенной переменной путем типизации буфера сообщается как 3.6854775808e + 4009 в отладчике ... RevExtended: = extended (Buffer); – DelphiFan

+0

Это тоже звучит не так. Я думаю, что пришло время для нас всех прекратить угадывание, и вы должны решить, что эти 10 байтов на самом деле. Почему вы все равно используете расширение? –

5

Номер, который вы хотите преобразовать это пример аномальному числа (см https://en.wikipedia.org/wiki/Extended_precision#x86_Extended_Precision_Format). Все допустимые числовые расширенные значения должны иметь явно сохраненный 1 бит в наивысшей позиции мантиссы (это отличается от одиночного и двойного, где высший бит подразумевается и скрывается, но не сохраняется).

Если этот бит равен нуль, то число аномальные, Вики говорят: только генерируются на 8087 и 80287. 80387, а позже рассматривать это как недопустимый операнд.

Операции над такими числами, которые были зависимыми от компилятора, например. Выходы BP7 ?.?<000000000000E-4882, но любые 32+ Delphi создают исключение.

+0

Ну, это почти правильно, за исключением того, что у денормалов этот бит не установлен, хотя они действительны. Однако денормалы должны иметь показатель всех нулей (т. Е. -16383). –