Pull to refresh

Comments 18

Самое веселье начинается в шейдерах. Например, если говорить о WebGL, то там целое число high precision integer на десктопе 32 разрядное, 4 байтное, т.е. до 4,294,967,296 , а вот на мобильных устройствах целое является 24 разрядным, т.е. до 16,777,216. И нигде про это не написано, нащупал методом граблей.

А прямо задаваемых типов нет? В C ведь придумали uint32_t и подобные и избежали неоднозначности между архитектурами.

Прямо такого нет. В шейдерах задаются int & float. Кроме того, можно вначале шейдера объявить точность таким вот образом:

precision highp int;

precision highp float;

float a;

Это означает, что для типа int & float будет использоваться максимально возможная точность. Только вот на разном железе она разная. На десктопах это int32, на мобильных устройствах int24.

Вообще-то это вот эта страница Эрика.
https://0.30000000000000004.com

И ещё — всего две функции — плюс н минус показаны. Где умножение, деление, где сравнение, т.к. с числами с плавающей запятой разлижные правила математики не работают, например X + Y иногда не равно Y + X. Не говоря уже об Y * (B * C) и (A * B) * C.

Так-же и правило малых чисел стоит упомянуть, как например этот пример и что из него будет:
1.5 × 10^20 + 100.5

Очень часто проверка на ноль может не работать.

почти наверняка там где получилось 0.30..04 все операции будут работать одинаково

А еще сложение в числах с плавающей запятой коммутативно, т.е. X + Y всегда равно Y + X (но не ассоциативно) (ну и если не брать в расчет NaN+NaN)

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

Проверка на ноль в мире float/double не работает ± всегда. Первое правило - задать достаточную в рамках задачи точность eps, в пределах которой два числа считаются равными. Правда тут начинаются интересности со сложением чисел с сильно разными порядками.

В самом интересном случае можно одним exe на двух компах получить в зоне "обычных" значение идентичные результаты, а в зоне, приближающейся к краю диапазона (~10^-20 для float) разницу в порядок-другой.

Проверка на ноль в мире float/double не работает ± всегда.

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

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

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

Все БД вовсе не используют плавающую запятую (возможность такая есть, обычно, но я не встречал в реальной жизни). У нас в системе приложены титанические усилия, что бы все вычисления проводились над типами с фиксированной точностью - ибо финансовые вычисления, и флоаты для них смерть. Вот и причина.

Ну БД просто по умолчанию старается в numeric, но float там есть, да и по примерам выше это видно.

мне кажется акцент статьи не туда смотрит, куда лучше объяснять всё на примерах того, как именно операции в "голове" у языка происходят. Например если вы хотите 0.1 умножить на целое, а потом прибавить опять дробное 0.3, то сразу вылезет проблема (в некоторых языках) с тем, что после умножения у вас будет целое и после сложения останется целое, то есть фактически 0.1 вы просто теряете, поэтому в разных языках формулу придется использовать по-разному или явно указывать тип, что-то вроде (double)(0.3*x)+0.1

Дроби это маленькая часть чисел с плавающей запятой. То, что ограничивается числами типа x.yz, легко решается путем перехода данных "от рублей к копейкам". Для операций со всем остальным приходится мириться, что не только данные представляются неточно, но и результат операций тоже вычисляется неточно. Ну, и конечно, a+b+c начинает зависеть от порядка вычислений.

Был баг на проде, где из файла читали целое в строке 13 и парсили в double получалось 12.999… и потом уже приводили к int. Жуткая штука

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

Насколько я знаю, зависит от локали системы, а не захардкожено.

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

import numpy as np
np.arange(0.1, 0.5, 0.1) # array([0.1, 0.2, 0.3, 0.4]) 
np.arange(0.6, 1.1, 0.1) # array([0.6, 0.7, 0.8, 0.9, 1. , 1.1])
np.arange(0.6, 1.0, 0.1) # array([0.6, 0.7, 0.8, 0.9])
np.arange(1.6, 2.1, 0.1) # array([1.6, 1.7, 1.8, 1.9, 2. ])
np.arange(0.6, 1.2, 0.1) # array([0.6, 0.7, 0.8, 0.9, 1. , 1.1])

Строка 2 нормальное логичное поведение из парадигмы питона, не учитывать последний элемента

Строка 3, ....

Строка 4,кажется что разработчики ненавидят цифру 1

Строка 5, почему не совпадает с 3!?

Строка 6, почему совпадает с 3!?

Мне кажется 3 и 4й примеры работы прекрасны. Разработчики numpy похожу что в курсе и в документации об этом как бы сказано(мне кажется это повод удалить саму функцию или запретить использование для float, а не писать что поведение ну типа странное).

Да, понимаю что float не так прост, но почему библиотека которая позиционирует себя как что-то для работы с точными вычислениями, такое выдает!? И вы еще боритесь за написание кода высокой культуры? Сколько скрытых ошибок благодаря такому поведению кода можно ожидать?

Sign up to leave a comment.