Как стать автором
Обновить
72
0
Артём Караваев @ArtemKaravaev

Математик-программист

Отправить сообщение

Благодарю, но это далеко не все особенности, о которых полезно знать. У меня на канале есть по этому поводу информация, если интересно. Да и вообще в интернете много про это пишут.


Есть ещё полезная статья David Goldberg, What Every Computer Scientist Should Know About Floating-Point Arithmetic, 1991

Благодарю! Вы правильно понимаете, если имеете в виду, что не само решение должно быть индивидуальным, а трудоёмкость округления (величина m) для каждой функции и для каждого режима округления подбирается индивидуально. Если мы точно знаем величину m, то есть то, до скольки битов после запятой нужно рассчитать промежуточный результат (до округления), то мы гарантированно получаем правильный ответ после округления, при этом верифицировать ничего не нужно, ответ будет гарантированно правильным сам по себе. Просто по определению величины m.


Сложность в том, чтобы эту величину m отыскать. Я привёл вариант решения, когда её ищут полным перебором с отсечениями. Для binary128 полный перебор как-то не хочет работать даже с отсечениями. Поэтому ждать вторую статью на эту тему от меня пока не надо, эту открытую научную проблему ещё никто не решил, и я пока тоже за неё не взялся :)

У меня округление выполняется в типе данных float, то есть имеется только 23 бита после запятой. В Wolfram используется иная внутренняя структура хранения чисел, там округление будет более точным, потому что двоичных битов больше.

Вы правильно помните алгебру, но неправильно поняли задачу. У нас не бесконечно много девяток после запятой, а всего шесть. И это именно два разных числа: 1,999999 и 2,0.


У числа с плавающей запятой (кроме нуля) может быть только одно правильное представление после корректного округления.

Я с вами полностью согласен, это UB, но поясню вам свою позицию. Дело в том, что в моей работе код пишется только под одну архитектуру и если нужно написать под другую, пишется другой код, такое правило. Причём пишется заново. Поэтому те вещи, которые в обычной жизни считаются UB, у меня считаются нормой и всегда работают в точности так, как я себе это представляю. То же касается битовых трюков, которые также нельзя было бы использовать. Ещё я пишу на этакой смеси C и C++, это тоже обусловлено постоянной работой на низком уровне. В общем, не судите строго, благодарю за замечание!


Здесь мне важно, чтобы читатели поняли суть, а как они это реализуют для себя — это уже пусть смотрят сами.

Ещё добавлю к цитате:


то дальше в ней либо все (до бесконечности) нули, либо где-то встретится единичка и результат будет ближе к верхнему значению округления

Нет, есть ещё третий вариант: нули превратятся в единички по ходу дальнейших расчётов. Потому что эти нули за пределами 0.5ulp. И вот если это произойдёт, тогда округление вверх даст другой результат.


UPD: Даже могу ещё точнее пример привести. Допустим, дробная часть мантиссы занимает два бита. Берём два числа, которые отличаются друг от друга меньше чем на 0.5ulp:
0.11000001
0.10111111
Наши 0.5ulp равны 0.125 (ценность последнего — второго — бита равна 0.25). Разница между числами значительно меньше. Но если округлять вверх оба, то будут разные результаты. Поэтому чтобы понять, куда же округлять на самом деле, нам нужно добраться в точности до 8-го бита. Аналогичные примеры можно придумать для любых вариантов округления.

Благодарю за вопрос! Вы ошибаетесь в том, что для округления вверх может быть другой пример, когда у нас, например, число 1.11000000001, и вы округлите вверх, получая 1.111, но вы заранее не знаете, этот паровоз из нулей — это уже правильный паровоз, или при последующих итерациях алгоритма на самом деле будет 1.1011111111? И тогда округление вверх должно дать 1.110. Опять ошибка в последнем бите. Короче говоря, для любого варианта округления есть своя ситуация, когда мы находимся очень близко к границе между двух направлений округления, и чтобы точно понять, с какой стороны от этой границы мы находимся, нужно чтобы паровоз из нулей или единиц точно закончился.

Совершенно верно, арифметика с плавающей запятой обладает целым рядом особенностей, поэтому такие вот вспомогательные функции типа FMA могут сделать жизнь лучше. Однако есть обратная сторона. Иногда (не всегда) FMA может работать заметно медленнее, чем отдельное умножение и сложение. Примером тому выступает код полного перебора (скрытый текст в статье), где как раз вычисляется полином в точке. Там если написать код через FMA, на моём компьютере становится в разы медленнее.

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность