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

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

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

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

Сообщение Сквозняк » 16.03.2017 16:44:10

Раньше числа с плавающей запятой обрабатывались по борландовски, правильно - ячейки памяти с мусором усекались и в дальнейшем не использовались. Теперь же глючит, зато по стандартам - как в питонах и прочих рубях.
Код: Выделить всё
var
Q: double;

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


Результат тестовой программы скомпилированной компилятором 2.6.4 версии:
Код: Выделить всё
3.00000000000000E-001
3.0000000000000000E-0001



Результат тестовой программы скомпилированной компилятором 3.0.0 версии:
Код: Выделить всё
2.9999999999999999E-001
3.00000000000000000011E-0001


В новом компиляторе произошла потеря точности при операциях с числами с плавающей запятой. Кто-нибудь в курсе, это случайно произошло или кто-то сознательно портирует баги из других ЯП чтобы в паскале лучше чем там не было?
Сквозняк
энтузиаст
 
Сообщения: 1109
Зарегистрирован: 29.06.2006 22:08:32

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

Сообщение Vadim » 16.03.2017 16:52:37

Зато если сделать вот так:
Код: Выделить всё
var
  Q: extended;

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

то результат получается просто замечательный:
3.00000000000000000011E-0001
3.00000000000000000011E-0001

:-)
Я думаю, что нам мягко намекают переходить с плавающей запятой только на один тип данных, а не мелочиться.
;-)
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

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

Сообщение Сквозняк » 16.03.2017 17:13:21

3.00000000000000000011E-0001


А что же тут замечательного? Мусор то появился, а значит он может накапливаться и ползти на следующие разряды.
Сквозняк
энтузиаст
 
Сообщения: 1109
Зарегистрирован: 29.06.2006 22:08:32

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

Сообщение Vadim » 16.03.2017 17:24:00

А Вы посчитайте, сколько ноликов после запятой было в версии 2.6.4 (там, где у Вас константы, естественно) и сколько этих же ноликов в моём примере. Если Вы после этого не поменяете мнение на счет мусора, то я съем Вашу шляпу. :-D В 2.6.4 Вы мусор просто не видели, а с типом ext - увидели, так что пока нет ничего сногсшибательного... ;-)
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

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

Сообщение Azazaz » 16.03.2017 17:35:27

Числа с плавающей точкой - игрушка дьявола, ежжи.
Количество значащих цифр для real типов ограничено, за пределами этого ограничения находится мусор. Для double это – 15 цифр приблизительно, дальше уже идет что угодно, как эта четверка например. В бытовых ситуациях 15 цифр – хватает с головой. Для вызова сатаны можно использовать Extended 10 байтовый.

Добавлено спустя 18 минут 30 секунд:
Тип / размер(byte) / точность(значащих цифр)
float 4 7
double 8 15
extended - 10 19
Azazaz
новенький
 
Сообщения: 41
Зарегистрирован: 21.04.2015 20:00:03

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

Сообщение zub » 16.03.2017 19:09:40

zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

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

Сообщение Сквозняк » 16.03.2017 19:46:40

Раз Double "улучшили", то у нас для вещественных чисел осталось только 2 нормальных типа: Extended и Currency?
Сквозняк
энтузиаст
 
Сообщения: 1109
Зарегистрирован: 29.06.2006 22:08:32

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

Сообщение zub » 16.03.2017 19:51:33

Как раз Double и стоит использовать.
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

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

Сообщение Сквозняк » 16.03.2017 22:46:33

Визуально содержимое нового Double вызывает желание его не использовать. Одно дело когда мусор где-то там за горизонтом и вылезает только в циклах, а другое, когда всё им засыпано.
Сквозняк
энтузиаст
 
Сообщения: 1109
Зарегистрирован: 29.06.2006 22:08:32

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

Сообщение zub » 16.03.2017 22:57:24

Незнаю про какое "нового Double" вы говорите. это дело давно стандартизовано, и новшеств в нем быть не может.
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

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

Сообщение Дож » 16.03.2017 23:18:15

Больше похоже на то, что Writeln по-другому печатает Double'ы.

Чтобы детальней обсуждать именно арифметику, лучше сделать дамп содержимого переменной Q. То, что там выводит Writeln, да ещё и в десятичном формате, не так интересно.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

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

Сообщение Сквозняк » 17.03.2017 02:11:02

zub писал(а):Незнаю про какое "нового Double" вы говорите. это дело давно стандартизовано, и новшеств в нем быть не может.
Однакоже в компиляторе 2.6.4 использовался борландовский стандарт и он был хорош. Паскаль всегда клал на чужие стандарты, что вдруг изменилось?

Добавлено спустя 14 минут 3 секунды:
Дож писал(а):Больше похоже на то, что Writeln по-другому печатает Double'ы.

Чтобы детальней обсуждать именно арифметику, лучше сделать дамп содержимого переменной Q. То, что там выводит Writeln, да ещё и в десятичном формате, не так интересно.


Именно десятичный формат и интересен - неинтересны не отображаемые последние разряды, неточность из которых выползет не скоро, если вообще успеет. Легко убедиться что поменялась общая логика обработки Double, а не только не во Writeln
Код: Выделить всё
var
S: string;
Q: double;

begin
Q:=0.1+0.2;
writeln(Q);
str(Q,S);
writeln(S);
end.
Сквозняк
энтузиаст
 
Сообщения: 1109
Зарегистрирован: 29.06.2006 22:08:32

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

Сообщение zub » 17.03.2017 02:25:15

Просветите, что за стандарт такой - борландовский?
Я вот в первом посте вижу повышение точности.
Попробуйте на бумажке написать как выглядят 0.1 0.2 0.3 с двоичной плавающей точкой?

Добавлено спустя 12 минут 40 секунд:
На лицо непонимание плавающей точки. Попробуйте такой вариант
Код: Выделить всё
var
S: string;
Q: double;
begin
Q:=0.1+0.2;
writeln(Q:1:14);
str(Q:1:14,S);
writeln(S);
readln;
end.


Добавлено спустя 56 секунд:
Сейчас на форуме неделя багоискателей. все дружно находят баги на ровном месте))
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

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

Сообщение Сквозняк » 17.03.2017 04:35:33

zub писал(а):Просветите, что за стандарт такой - борландовский?

То как Борланд реализовал в своих продуктах.

zub писал(а):Попробуйте на бумажке написать как выглядят 0.1 0.2 0.3 с двоичной плавающей точкой?

Там будет не один вариант. Самый простой, это если не прятать, локализовать и т.д. баги. А другие - если этим заниматься.
Код: Выделить всё
var
Q: double;
E: extended;
L: int64;

begin
Q:=0.1+0.2;
L:=trunc(frac(Q)*100000000);
writeln(L);
E:=0.1+0.2;
L:=trunc(frac(E)*100000000);
writeln(L);
readln;
end.

Результат этого теста одинаковый для компиляторов 2.6.4 и 3.0.0 Из чего делается вывод что в extended баг двоичной записи числа отлично локализуется в независимости от того, как этот тип теперь реализован. К сожалению double показал худший результат, и в новом компиляторе его даже не пытаются подправить.
Сквозняк
энтузиаст
 
Сообщения: 1109
Зарегистрирован: 29.06.2006 22:08:32

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

Сообщение zub » 17.03.2017 05:12:57

Какието далекоидущие выводы. На основе чего? мне непонятно
Double одинаков в транке и в 2.6.4. Различие в процедуре округления к десятичному виду, т.е. только в том что вы видете на экране. в памяти и в прцессе вычислений всё идентично.
Код: Выделить всё
uses sysutils;
procedure DumpBytes(const name:string;const a;const len:integer);
var i:integer;
    pb:pbyte;
begin
  pb:=@a;
  write(format('%10s:',[name]));
  for i:=0 to len-1 do
  begin
    write(format('%3x',[pb^]));
    inc(pb);
  end;
  write(format(' general number:%g',[double(a)]));
  writeln;
end;
var
  q:double;
begin
  q:=0.1;
  DumpBytes('0.1',q,sizeof(q));
  q:=0.2;
  DumpBytes('0.2',q,sizeof(q));
  q:=0.3;
  DumpBytes('0.3',q,sizeof(q));
  q:=0.1+0.2;
  DumpBytes('0.1+0.2',q,sizeof(q));
  readln;
end.


транк:
Код: Выделить всё
0.1: 9A 99 99 99 99 99 B9 3F general number:0,10000000000000001
0.2: 9A 99 99 99 99 99 C9 3F general number:0,20000000000000001
0.3: 33 33 33 33 33 33 D3 3F general number:0,29999999999999999
0.1+0.2: 33 33 33 33 33 33 D3 3F general number:0,29999999999999999


2.6.4
Код: Выделить всё
0.1: 9A 99 99 99 99 99 B9 3F general number:0,10000000000000001
0.2: 9A 99 99 99 99 99 C9 3F general number:0,20000000000000001
0.3: 33 33 33 33 33 33 D3 3F general number:0,29999999999999999
0.1+0.2: 33 33 33 33 33 33 D3 3F general number:0,29999999999999999


привычные нам "короткие" дроби на подобии 0.1, 0.2, 0.3 не имеют в двоичном формате точного конечного представления. это вас и вводит в заблуждение
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

След.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 18

Рейтинг@Mail.ru