Неожиданный результат от функции Max в FreePascal - PullRequest
0 голосов
/ 25 августа 2018

Рабочий пример действительно прост для понимания:

program Project1;

uses
SysUtils, Math;

var
  fValue: double;
  fValueMax: double;
begin
  fValue := 7.0207503445953527;
  fValueMax := Max(0, fValue);
  writeln(fValue);
  writeln(fValueMax);
  readln;
end.   

Однако результат совершенно неожиданный. По какой-то причине функция Max не только возвращает большее число из двух аргументов, но и меняет его значение.

В приведенном выше примере кода ожидаемое значение fValueMax в точности равно fValue, но вместо этого fValueMax больше. Разница примерно в E-7, такая маленькая, но все же неожиданная и вылетает мой следующий код (который не публикуется здесь для ясности и простоты вопроса).

1 Ответ

0 голосов
/ 25 августа 2018

Я должен заявить заранее, что последний раз, когда я использовал Паскаль, было около 25 лет назад. Но я из любопытства вытащил Free Pascal и попробовал это:

program Project1;

uses
SysUtils, Math;

var
  fValue: double;
  fValueMax: double;

  fSingle: single;

  fValue2: double;
  fValue2b: double;
  fValueMax2: double;

begin
  fValue := 7.0207503445953527; 
  fSingle := 7.0207503445953527;
  fValueMax := Max(0, fValue);

  writeln(fValue);       // prints 7.0207503445953527E+000
  writeln(fValueMax);    // prints 7.0207505226135254E+000

  writeln(fSingle);      // prints 7.020750523E+00

  fValue2 := 7.0207503445953527;
  fValue2b := 0.0;
  fValueMax2 := Max(fValue2b, fValue2);

  writeln(fValue2);      // prints 7.0207503445953527E+000
  writeln(fValueMax2);   // prints 7.0207503445953527E+000
  readln;
end.

Мои первые две команды writeln показывают тот же результат, который вы сообщали. Я подозревал, что, возможно, Max возвращает значение с меньшей точностью, чем double, который вы ожидали получить, поэтому я создал fSingle и присвоил ему тот же литерал, что и для fValue, и, конечно же, его значение выглядит очень близко к тому, что вы получаете обратно в fValueMax.

Итак, наконец, вместо вызова Max с fValue и литералом 0, я назвал его двумя переменными типа double, одну из которых я установил на 0.0. В этом случае вы можете видеть, что вход (fValue2) и выход (fValueMax2) имеют абсолютно одинаковое значение. Поэтому, хотя я не знаю точно, какие правила Паскаля определяют, какую перегрузку вызывать, мне интересно, был ли ваш исходный вызов Max как-то разрешен до версии, которая принимает два значения single и возвращает то же самое.

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

...