fpc-3.0.0 - запилили баг в арифметику

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Ответить
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

Сообщение Дож »

Именно десятичный формат и интересен - неинтересны не отображаемые последние разряды, неточность из которых выползет не скоро, если вообще успеет. Легко убедиться что поменялась общая логика обработки Double, а не только не во Writeln

Код: Выделить всё

var
S: string;
Q: double;

begin
Q:=0.1+0.2;
writeln(Q);
str(Q,S);
writeln(S);
end.

Вы, наверное, так шутите? :/ Вы говорите про общую логику обработки Double, и сразу после этого приводите фрагмент кода, в котором преобразовываете этот самый Double при помощи Str во что-то другое? Нет, это не общая логика обработки Double, это какая-то логика про строки.

Разверну уже высказанную ранее мысль: нужно смотреть именно содержимое переменной Q, а не результаты её преобразований во что-то другое. Лучше всего прям дамп памяти, бинарный или Hex. Нужно понять чему равна мантисса, чему равна экспонента, в старой и новой версиях. После этого можно вычислить точность обоих вариантов и посмотреть как эта точность различается. Это уже получится предметное обсуждение именно общей логики работы с Double.
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

zub
Если человек своим зорким оком хочет проверить правильность вычисления, то ничем, кроме как выводом на экран (или в файл), это не сделать. Согласитесь, может же быть такое, что в процессе поиска алгоритма вычисления чего либо точного (до некоторых пределов, естественно ;-) ) алгоритм подбирается по выводимому результату.
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

Дож писал(а): После этого можно вычислить точность обоих вариантов и посмотреть как эта точность различается. Это уже получится предметное обсуждение именно общей логики работы с Double.


Знаешь, это похоже на любимое развлечение математиков -- нахождение последнего знака числи Пи. в реальности же для этого нет смысла.
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

Vadim
ок, проверяем

Код: Выделить всё

begin
  if ((0.7-0.3)/(0.5-0.1))=1 then
    writeln('=')
  else
    writeln('<>');
  readln;
end. 
Последний раз редактировалось zub 17.03.2017 08:26:01, всего редактировалось 1 раз.
Аватара пользователя
vitaly_l
долгожитель
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41
Контактная информация:

Сообщение vitaly_l »

Код: Выделить всё

var
S: string;
Q: double;

begin
Q:=0.1+0.2;
writeln(Q);
writestr(s,Q :10:5);
writeln(s);
end. 
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

а еще лучше проверять вот это, обязательно зорким глазом

Код: Выделить всё

begin
  if ((0.7-0.3)/(0.5-0.1))=1.0000000000000000E+0000 then
    writeln('=')
  else
    writeln('<>');
  writeln((0.7-0.3)/(0.5-0.1));
  readln;
end. 

и делать это строго на 1.6.4, т.к. он специально для глазастых выведет

Код: Выделить всё

<>
 1.0000000000000000E+0000

транк жалеет мозги и выводит

Код: Выделить всё

<>
 9.99999999999999999946E-0001

ТС, ты еще не пересмотрел мнение где баг, а где он пофикшен?
Последний раз редактировалось zub 17.03.2017 09:19:24, всего редактировалось 2 раза.
Аватара пользователя
vitaly_l
долгожитель
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41
Контактная информация:

Сообщение vitaly_l »

zub писал(а):if ((0.7-0.3)/(0.5-0.1))=1 then

проверьте лучше вот так:

Код: Выделить всё

var
Q: double;
QQ: double;
begin
Q  := 0.7-0.3;
QQ := 0.5-0.1;
if (Q/QQ)=1 then
  writeln('=')
else
  writeln('<>');   

end.
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

Нет, не лучше. тут совсемм другие причины
Аватара пользователя
vitaly_l
долгожитель
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41
Контактная информация:

Сообщение vitaly_l »

zub писал(а):Нет, не лучше. тут совсемм другие причины

Ну какие другие-то? Приведите к единому типу, а потом вычисляйте.
Это всё таки компьютер, а не калькулятор и ему нужно точно указать что именно считать.
Итог: У меня результат верный, а у Вас ошибка. Вот и всё.
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

>>Ну какие другие-то?
я ссылку давал на предидущей странице - почитай. или погугли, на эту тему немало палок сломано.

>>Итог: У меня результат верный, а у Вас ошибка. Вот и всё.
итог - какраз у меня вычислино более точно, т.к. результат еденице не равен))
Аватара пользователя
vitaly_l
долгожитель
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41
Контактная информация:

Сообщение vitaly_l »

zub писал(а):результат еденице не равен))

А что, разве математики уже догадались что, 0.4 / 0.4 не равно 1 ?
По моему у математиков, результат деления 0.4 / 0.4 равен 1. Или это не так?
Что в системе Си заложено у этих дикарей? Единица или правильное значение?
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

ты прочитал?
Аватара пользователя
vitaly_l
долгожитель
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41
Контактная информация:

Сообщение vitaly_l »

zub писал(а):ты прочитал?

Код: Выделить всё

var
R:Single; 
 begin
  R:=0.1;
  if R=0.1 then
   writeln('=')
  else
   writeln('<>')
 end. 

О "круто"!!! Я не знал... И получается это до сих пор никто не исправил? Офигеть!
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

vitaly_l, дело в том, что когда в действие идут вещественные числа, то понятие точное соответствие становится чисто теоретическим. И если на бумаге еще можно как-то посчитать, то у компов есть маленький нюанс -- они не записывают числа точно.

Конечно, это не так критично в математических пакетах, но там другой подход. Да и там периодически находятся ошибки -- главное подобрать правильно тестовые примеры.
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

Я незнаю как ты будешь после этого жить, в мире дикарей. но както вот так:

Код: Выделить всё

uses sysutils;
procedure DumpBytes(const name:string;const a;const len:integer);
var i:integer;
    pb:pbyte;
    s:string;
begin
  pb:=@a;
  write(format('%19s:',[name]));
  for i:=0 to len-1 do
  begin
    write(format('%3x',[pb^]));
    inc(pb);
  end;
  case len of
     4:str(single(a),s);
     8:str(double(a),s);
     10:str(extended(a),s);
  end;
  write(format(':%s',[s]));
  writeln;
end;
var
  q:{double}extended;
begin
  q:=0.7-0.3;
  DumpBytes('0.7-0.3',q,sizeof(q));
  q:=0.5-0.1;
  DumpBytes('0.5-0.1',q,sizeof(q));
  q:=(0.7-0.3)/(0.5-0.1);
  DumpBytes('(0.7-0.3)/(0.5-0.1)',q,sizeof(q));
  readln;
end.

Код: Выделить всё

            0.7-0.3: CC CC CC CC CC CC CC CC FD 3F: 3.99999999999999999978E-0001
            0.5-0.1: CD CC CC CC CC CC CC CC FD 3F: 4.00000000000000000005E-0001
(0.7-0.3)/(0.5-0.1): FF FF FF FF FF FF FF FF FE 3F: 9.99999999999999999946E-0001

раскоменти q в double, и ты увидешь свои циферки с "пониженой" точностью

Код: Выделить всё

            0.7-0.3: 9A 99 99 99 99 99 D9 3F: 4.0000000000000002E-001
            0.5-0.1: 9A 99 99 99 99 99 D9 3F: 4.0000000000000002E-001
(0.7-0.3)/(0.5-0.1):  0  0  0  0  0  0 F0 3F: 1.0000000000000000E+000


но т.к. промежуточные вычисления идут в extended: (0.7-0.3) как и (0.5-0.1) не 0.4 и соответственно (не 0.4)/(не 0.4)<>1
Ответить