LINUX.ORG.RU
решено ФорумTalks

питонопроблемы

 ,


2

3

чему у вас равно 3.11 + 2?

UPD: протупил, причина то тривиальная, забыл, что в double порядки двоичные, теперь разбираюсь, почему 5.11 = 5.11

★★★★★

Последнее исправление: cvs-255 (всего исправлений: 2)
Ответ на: комментарий от Singularity

аналогично. И что характерно,

5.11 - 3.11 = 2.0000000000000004
5.11-3.11 - 2 = 4.440892098500626e-16
5.11-(3.11 + 2) = 8.881784197001252e-16

Хотя для 2 цифр после точки точности double хватать должно за глаза

cvs-255 ★★★★★
() автор топика
Последнее исправление: cvs-255 (всего исправлений: 1)
Ответ на: комментарий от cvs-255

В удалённом комментарии погрешности от усечения должны аннигилировать. Почему 0.11 = 0.11 я не знаю :)

d_a ★★★★★
()
Ответ на: комментарий от d_a

да, я протупил вначале, потом понял и удалил

cvs-255 ★★★★★
() автор топика

Классическая же проблема, чему тут люди удивляются

ZERG ★★★★★
()

Умные ребятки тут, как то давали ссылочку https://en.wikipedia.org/wiki/Floating-point_arithmetic что так и должно быть.

Вот что дает javascript https://jsfiddle.net/pxczecb4/

Руби

puts 3.11 + 2
5.109999999999999

Лисп(право я нашел онлайн интерпритатор)

(write-line (+ 3.11 2))
*** - WRITE-LINE: argument 5.1099997 is not a string

ggrn ★★★★★
()
Ответ на: комментарий от cvs-255

в octave, например, не наблюдается такого

А в октаве у вас режим вывода какой? По дефолту, там до округление до 5 знаков (format short).

d_a ★★★★★
()
Последнее исправление: d_a (всего исправлений: 1)
Ответ на: комментарий от ggrn

это я уже вспомнил, что в double порядки двоичные, а не десятичные, а потому дробь бесконечная получается. Осталось понять только, почему 5.11 выводится как 5.11?

cvs-255 ★★★★★
() автор топика
Ответ на: комментарий от cvs-255

Мне кажется надо копать в сторону того, как строка 5.11 стала числом 5.11 (а потом снова строкой 5.11, чтобы напечататься вам в пыхтонговский REPL).

d_a ★★★★★
()
Последнее исправление: d_a (всего исправлений: 1)
Ответ на: комментарий от d_a

Меня то вначале в заблуждение ввело именно это. Я подумал, что раз 5.11 выводится нормально, а не 5.109999999999999, то значит с точным представлением этого числа проблем нет

Хотя кажется уже разобрался

cvs-255 ★★★★★
() автор топика
Последнее исправление: cvs-255 (всего исправлений: 1)

Опять кто-то не в курсе того, как устроены компутеры

anonymoos ★★★★★
()

В haskell результат аналогичный:
5.1099997 для Float
5.109999999999999 для Double

najlus ★★★★★
()

Ты еще 0.1+0.2 посчитай

af5 ★★★★★
()

Тогда у меня вопрос, почему:

>>> 3.11 + 2
5.109999999999999


а


[quote][quote][quote] 5.11 + 2[br][/quote][/quote][/quote]7.11

?

julixs ★★★
()

А вот на Perl 6 всё правильно:

[xxxxx ~]$ perl6
To exit type 'exit' or '^D'
> say 3.11 + 2;
5.11
> say 3.11 + 2 == 5.11;
True
PHPFan
()
Ответ на: комментарий от Dred

возвращаюсь к вопросу, при чем тут питон ?

Сложил числа в переменной доубле в паскале - ну нету такой лажи на таких маленьких числах! Это питонопроблема - у них же всё объекты со своим неочевидным поведением. И вдобавок исходники самого питона в основном на сях, в пакете с полсотни патчей - дикий зоопарк.

Napilnik ★★★★★
()
Ответ на: комментарий от Napilnik

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

Dred ★★★★★
()

не вижу проблемы. Все работает, как ожидается. Хочешь точность до двух цифр — округляй. А точность до n-той цифры тебе только длинная арифметика гарантирует.

dikiy ★★☆☆☆
()
Последнее исправление: dikiy (всего исправлений: 1)
Ответ на: комментарий от cvs-255

почему 5.11 выводится как 5.11?

Потому что в функциях вывода стоит какая-то точность по умолчанию.

почему 5.11 = 5.11

А почему не должно быть? Транслятор берет этот литерал и преобразует в какое-то ближайшее к 5.11 число. Если ты во время лексинга (а в большинстве языков вмешаться в лексинг невозможно) не меняешь правила округления, то это будут два одинаковых числа, неравных точно 5.11

buddhist ★★★★★
()
Ответ на: комментарий от cvs-255

https://github.com/python/cpython/blob/master/Objects/floatobject.c#L323

https://github.com/python/cpython/blob/master/Python/pystrtod.c#L821

Здесь написано, что по умолчанию точность — 17 позиций

Дробь 5.10999999999(9) по умолчанию начинает выводиться как 5.11 после достижения 16 знаков после запятой

buddhist ★★★★★
()
Ответ на: комментарий от Dred

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

Это - необычное поведение для _коротеньких_ чисел с плавающей запятой. Если бы знаков было _много_, тогда и следовало ожидать «такого обычного поведения», а если для округлений хватает уже трёх знаков в ЯП, в котором погромист явно не задавал лажотип данных, то это звиздец.

Napilnik ★★★★★
()
Ответ на: комментарий от Napilnik

Это - необычное поведение для _коротеньких_

а кто решает какие коротенькие ? это вообще не от этого зависит, а от того как число в бинарном виде выглядит.

например если складывать 5.11 + 2 все окей, если .11 + 2 тоже. Но вот 1.11 и тд уже нет. Можно еще смотреть на различия c помощью float.hex раз уж так хочется. Мне нет например

Dred ★★★★★
()
Ответ на: комментарий от dikiy

не вижу проблемы. Все работает, как ожидается. Хочешь точность до двух цифр — округляй. А точность до n-той цифры тебе только длинная арифметика гарантирует.

А типы переменных для чисел с запятой Real, Single, Double, Extended (задействовано 10 байтов), Comp, Currency придуманы не в нашей галактике? Вывод: если хочешь предсказуемой точности, то используй нормальные ЯП а не скриптовые средства для автоматизации логики в играх, написанные на куче чужих ЯП, со множеством уникальных патчей в каждом дистрибутиве. Реально, если программа на питоне написана в дистрибутиве X, то как ожидать что она так будет работать и в Y? Бубунтопрограмма на сях хоть с большой вероятность свалится с сегфолтом в другом дистре, а эти скриптоязыки придуманы чтобы при глюках продолжать работу, вот они и работают - считают с багами «длиннейшие» числа из трёх знаков.

Napilnik ★★★★★
()
Последнее исправление: Napilnik (всего исправлений: 1)
Ответ на: комментарий от Dred

а кто решает какие коротенькие ? это вообще не от этого зависит, а от того как число в бинарном виде выглядит.

В нормальных ЯП, в точных типах переменных, это уже десятки лет реализовано. Выбираешь тип Double или Extended и на числах с тремя знаками и запятой точно всё будет точно, просто не паришься. Есть даже тип переменных для бухгалтерских расчётов (название без шпаргалки не вспомню), в нём стабильно 3 знака после запятой и округляются они именно так, как принято в бугалтерии.

Napilnik ★★★★★
()
Ответ на: комментарий от Napilnik

В нормальных ЯП, в точных типах переменных, это уже десятки лет реализовано.

Ну не у всех же дома мейнфреймы IBM стоят.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Ну не у всех же дома мейнфреймы IBM стоят.

ПК достаточно: по сравнению с тем ПК, на котором Линус начал писать линукс, они сильно ускорились и увеличили количество памяти. А если всё считать в зависящем от платформы типе Real, то получите долю процента прироста скорости и хреновый результат.

Napilnik ★★★★★
()
Ответ на: комментарий от i-rinat

Смотри на форматы http://www.delphibasics.ru/1Type.php ЯП - родственные и производные, в которых самое главное из этого есть. В питоне куча потрохов на сях, на них конечно сложно написать несегфолтящегося монстра, но хотя бы тип Double для чисел с запятой как минимальный задать было можно - хоть на нетелефонном железе поработало бы точнее.

Napilnik ★★★★★
()
Ответ на: комментарий от i-rinat

И ты считаешь, что в Double в Delphi таких проблем нет?

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

А ничего, что в Python абсолютно тот же формат используется?

А ничего. После того как пересчитал на паскале, полез в поисковик искать на чём же таком написан интерпретатор питона, получил в ответ подобие ответа и качнул питоновскую src.rpm из федоровских реп. Вот там звиздец и вылез - патчей к исходникам 50 с копейками, в самих исходниках потроха и на сях и на чёрте лысом - хрен сразу разберёшь, даже если постараешься, сколько раз данные конвертируются в другие форматы когда скачут от кода на одном ЯП к другому.

Napilnik ★★★★★
()
Ответ на: комментарий от Napilnik

меня раньше скакал знак 15 и выше, а тут в сообщении такой эпический провал.

facepalm.ieee754

Пересчитай в своём FPC ещё раз. Только убедись, что число не корёжится при выводе на печать.

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 1)
Ответ на: комментарий от i-rinat

Если ты про палево, то не отрицаю что прямо сейчас немного шпилю в рпг, перс киркой землю колотит - в линуксе такое не запускается, поскольку жадные админы запилили неработу изделия во всех виртуалках, которые знают и могут протестить. Следовательно, fpc 2.6.4 отработал в маздайке - в линуксе тест был ночью.

var
Q1: DOUBLE;

begin
WRITELN('QQQQQQQQQQQQQQQQQQQQQQ');
Q1:=1.2345678901234567890;
WRITELN(Q1);
Q1:=Q1+3;
WRITELN(Q1);
Q1:=Q1+200;
WRITELN(Q1);
end.
Из консоли результат работы программы что-то не копипастится, потому выкладываю скрин http://i89.fastpic.ru/big/2017/0315/1d/ba2d36b3a87e38c20ddda298a178351d.png

Napilnik ★★★★★
()
Ответ на: комментарий от Napilnik

1.2345678901234567890

Что-то не очень на 5.11 похоже.

Из консоли результат работы программы что-то не копипастится

Позорище какое.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Что-то не очень на 5.11 похоже.

Вопрос был про пятнадцать знаков, ты их получил. Если тебе нужны ещё и 3, то получи и их. И чтобы ещё раз не писать, тест про сложение во Writeln по умолчанию, без явного задания типа переменной. По количеству знаков можно догадаться что используется что-то помощнее Double

var
Q1,W1: DOUBLE;

begin
WRITELN('QQQQQQQQQQQQQQQQQQQQQQ');
Q1:=1.2345678901234567890;
WRITELN(Q1);
Q1:=Q1+3;
WRITELN(Q1);
Q1:=Q1+200;
WRITELN(Q1);
WRITELN('WWWWWWWWWWWWWWWWWWWWWWWWWWW');
W1:=5.11;
WRITELN(W1);
W1:=3.11;
WRITELN(W1);
W1:=W1+2;
WRITELN(W1);
WRITELN('|||||||||||||||||||||||||');
WRITELN(3.11+2);
end.

И традиционный результат в виде скриншота консоли:)

http://i90.fastpic.ru/big/2017/0315/35/f8023efa2afbc21e43e636778bde4035.png

Napilnik ★★★★★
()
Последнее исправление: Napilnik (всего исправлений: 1)
Ответ на: комментарий от Napilnik

можно догадаться

WRITELN(3.11+2);

Я же говорил тебе: «убедись, что число не корёжится при выводе на печать».

i-rinat ★★★★★
()
Ответ на: комментарий от Napilnik

Какой же ты дурак всё-таки. IEEE 754, тебе говорят. Ты не можешь в двоичной системе представить 0.11 в виде конечной дроби. Только костылями в виде тормозного decimal.

mix_mix ★★★★★
()
Ответ на: комментарий от i-rinat

Я же говорил тебе: «убедись, что число не корёжится при выводе на печать».

Корёженья не обнаружил. Не знаю, о чём ты.

Napilnik ★★★★★
()
Ответ на: комментарий от mix_mix

От питонолоха и слышу. Свои стандарты чисел для суперкомпьютеров на калькуляторах можешь засунуть себе поглубже и не светить на людях. В нормальных процессорах для вычислений есть родной тип данных Extended, умные ЯП при необходимости могут сделать из него типы попроще, это если нет других быстрых вариантов. А тормоза что у питонов, что у плюсов и так растут семимильными шагами - они просто опухли от тупых решений котрорые может быть были ещё ничего на компах с 16Мб озу и диском в 250Мб, а сейчас требуют SSD для нормальной работы. Всё там качается и линкуется большими кусками на каждый чих, а менеджер памяти ищет подходящие куски пространства и занимается дефрагментацией когда нужных кусков не обнаружит.

Napilnik ★★★★★
()
Ответ на: комментарий от Napilnik

Корёженья не обнаружил. Не знаю, о чём ты.

Я про WRITE(). Ты знаешь, как она устроена внутри? Или так, на вывод посмотрел?

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Смотрел когда-то на реализацию базовых процедур и фукнкций. Ну что сказать, что-то реализовано самим ЯП, что-то берётся из операционок. Плохое по возможности не берётся и реализуется самим ЯП. Что конкретно во WRITE() не устраивает?

Napilnik ★★★★★
()
Ответ на: комментарий от Napilnik

Что конкретно во WRITE() не устраивает?

Я не говорю, что в ней что-то не устраивает. Ты знаешь, как она работает? Можешь в точности расписать алгоритм работы? Описание, достаточное для создания сторонним человеком реализации с точно таким же поведением Write().

i-rinat ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.