В первые же дни изучения Java я наткнулся на такой любопытный вид примитивов, как числа с плавающей точкой. Меня сразу заинтересовали их особенности и, тем более, способ записи в двоичном коде (что взаимосвязано). В отличие от какого-либо диапазона целых чисел, даже в очень малом промежутке (например от 1 до 2) их бесконечное множество. И имея конечный размер памяти, невозможно выразить это множество. Так как же они выражены в двоичном коде и как работают? Увы, объяснения в вики и достаточно клёвой статьи на хабре тут не дали мне полного понимания, хотя заложили базу. Осознание пришло лишь после этой статьи-разбора наутро после прочтения.
(почерпнул из этой статьи на Хабре
Каждый компьютер делал это по-своему, и ошибки были у каждого свои. Но в середине 70-х компания Intel решила сделать новые процессоры с поддерживаемой «улучшенной» арифметикой и заодно стандартизировать её. Для разработки привлекли профессоров Уильяма Кэхэна и Джона Палмера (нет, не автора книг про пиво). Не обошлось без драм, но всё же новый стандарт был разработан. Сейчас этот стандарт называют IEEE754Ещё в учебниках школьного курса все сталкивались с непривычным способом записи очень больших или очень малых чисел вида 1,2×103 или 1,2E3, что равно 1,2×1000 = 1200. Это называется способ записи через экспоненту. В данном случае мы имеем дело с выражением числа по формуле: N=M×np, где
В данном случае и когда речь не идёт о компьютерах, основанием выступает цифра 10Довольно часто основание порядка подразумевается, как 10 и записывают лишь мантиссу и значение степени основания, разделяя их буквой E. В нашем примере я привёл равнозначные записи 1,2×103 и 1,2E3 Если всё понятно, и ностальгический экскурс в школьную программу мы закончили, то сейчас рекомендую забыть это, т. к. при формировании числа с плавающей точкой мы имеем дело со степенями двойки, а не десятки, т.е.
И что мы имеем? В итоге мы также имеем двоичное число, которое состоит из мантиссы — часть, которую будем возводить в степень и саму степень. Кроме этого, так же как принято и у целочисленных типов, в числах с плавающей точкой есть бит, который определяет знак — будет число положительным или отрицательным.
В качестве примера предлагаю рассмотреть тип float, который состоит из 32 бит. С числами двойной точности double логика такая же, только в два раза больше бит.
Из 32 бит, первый старший отводится на знак, следующие 8 бит отводятся на экспоненту — степень, на которую будем возводить мантиссу, а остальные 23 бита — на мантиссу.
Для демонстрации давайте посмотрим на пример пример:
С первым битом всё очень просто. Если значение первого бита 0, то число, которое мы получим будет положительным. Если бит равен 1, то число будет отрицательным.
Следующий блок из 8 бит — блок с экспонентой.
Экспонента записывается как обычное восьмибитное число, а чтоб получить требуемую степень нам нужно из полученного числа вычесть 127 В нашем случае восемь бит экспоненты — это 10000001. Это соответствует числу 129. Если есть вопрос, как это посчитать, то на картинке быстрый ответ.
Развёрнутый можно получить на любом курсе булевой алгебры. 1×27 + 0×26 + 0×25 + 0×24 + 0×23 + 0×22 + 0×21 + 1×2
Теперь о мантиссе.
Она состоит из 23 бит, однако в начале всегда подразумевается ещё одна единица, на которую биты не выделяются.
Это сделано в целях целесообразности и экономии. Одно и то же число можно выражать разными степенями, добавляя к мантиссе нули перед или после запятой.
Проще всего это понять с десятичной экспонентой: 120 000 = 1,2×105 = 0,12×106 = 0,012×107 = 0,0012×108 и т.д.
Однако, введя фиксированное число в голове мантиссы мы каждый раз будем получать новые числа. Примем как данность, что перед нашими 23 битами будет ещё один с единицей. Обычно этот бит от остальных отделают точкой, которая, впрочем, ничего не значит. Просто так удобнее
1 . 11100000000000000000000
Теперь полученную мантиссу нужно возводить в степень слева направо, уменьшая с каждым шагом степень на одну. Стартуем со значения степени, который мы получили в результате вычисления, т. е. 2 (Я специально выбрал простой пример, чтоб не писать каждое значение степени двойки и в приведенной таблице не вычислял их, когда соответствующий бит равен нулю)
Стандартное число с плавающей точкой типа float состоит из 32 бит, первый бит — знак (+ или -), следующие восемь — экспонента, следующие 23 — мантисса
По знаку — если бит 0 — число положительное.
Если бит 1 — отрицательное. По экспоненте — побитно переводим в десятичное число (первый слева бит — 128, второй — 64, третий — 32, четвёртый — 16, пятый — 8, шестой — 4, седьмой — 2, восьмой — 1
Число с плавающей запятой состоит из:
Нормальной формой числа с плавающей запятой называется такая форма, в которой мантисса (без учёта знака) находится на полуинтервале [0; 1).
В вычислительных машинах показатель степени принято отделять от мантиссы буквой «E» (exponent). Например, число 1,528535047 × 10 -25 в большинстве языков программирования высокого уровня записывается как 1.528535047E-25.
Существует несколько способов того, как строки из цифр могут представлять числа:
То есть в мантиссе запятая помещается сразу после первой значащей (не равной нулю) цифры, считая слева направо, а дальнейшая запись даёт информацию о действительном значении числа. Например, период обращения (на орбите) спутника планеты Юпитера Ио́, который равен 152853,5047 с, в стандартном виде можно записать как 1,528535047 × 105. Побочным эффектом ограничения на значения мантиссы является то, что в такой записи невозможно изобразить число 0.
Кроме того, в двоичной записи мантисса обычно денормализована, то есть запятая подразумевается до первой цифры, а не после, и целой части вообще не имеется ввиду — так появляется возможность и значение 0 сохранить естественным образом. Таким образом, десятичная 9 в двоичном представлении с плавающей запятой будет записана как мантисса +1001000…0 и показатель +0…0100. Отсюда, например, беды с двоичным представлением чисел типа одной десятой (0,1), для которой двоичное представление мантиссы оказывается периодической двоичной дробью — по аналогии с 1/3, которую нельзя конечным количеством цифр записать в десятичной системе счисления.Запись числа в форме с плавающей запятой позволяет производить вычисления над широким диапазоном величин, сочетая фиксированное количество разрядов и точность. Например, в десятичной системе предоставления чисел с плавающей запятой (3 разряда) операцию умножения, которую мы бы записали как
в нормальной форме представляется в виде

В формате с фиксированной запятой мы бы получили вынужденное округление
Мы потеряли крайний правый разряд числа, так как данный формат не позволяет запятой «плавать» по записи числа.
Диапазон чисел, которые можно записать данным способом, зависит от количества бит, отведённых для представления мантиссы и показателя. На обычной 32-битной вычислительной машине, использующей двойную точность (64 бита), мантисса составляет 52 бита + 1 знаковый, показатель — 11 бит. Таким образом получаем диапазон точности примерно от 4,94 × 10−324 до 1.79 × 10308 (от 2−52 × 2−1022 до ~1 × 21024). Пара значений показателя зарезервирована для обеспечения возможности представления специальных чисел. К ним относятся значения бесконечность), получающихся в результате операций типа деления на ноль нуля, положительных и отрицательных чисел.
2\text{kg}/\text{s}\). Если мы изменим только последнюю цифру с \(8\) на \(9{-15}\), в котором по-прежнему 7 цифр, но только 21 десятичный знак.
Можно легко спутать термины точность и точность , особенно если посмотреть на результат вычисления на компьютере. Точность числа с плавающей запятой всегда равна \(d\) двоичным разрядам, но не все эти разряды могут точно представлять предполагаемое значение.
Предположим, что \(x\) представляет интерес, а \(\tilde{x}\) является его приближением. Абсолютная точность из \(\tilde{x}\) равно
\[|\tilde{x} — x|,\]
, а относительная точность равна
\[\frac{|\tilde{x} — x|}{|x|},\]
Абсолютная точность имеет те же единицы измерения, что и \(x\), а относительная точность безразмерна. Мы также можем выразить относительную точность как
(5)\[\text{точные цифры} = -\log_{10} \left| \frac{\tilde{x}-x}{x} \right|.\]
Мы часто округляем это число до целого числа, но имеет смысл говорить о «почти семизначном» или «десяти с половиной цифрах».
цифры». 9{-1022}\), что является наименьшим положительным числом двойной точности. Первое связано с относительной точностью, а второе — с абсолютной точностью. Чтобы приблизиться к нулю, всегда требуется сдвиг мышления в сторону абсолютной точности, потому что любая конечная ошибка бесконечна по отношению к нулю.
Следует отметить еще одно значение двойной точности: NaN, что означает Not a Number . Это результат неопределенной арифметической операции, такой как 0/0.
Компьютерная арифметика выполняется над числами с плавающей запятой и возвращает результаты с плавающей запятой. Мы предполагаем существование машинно-аналоговых операций для вещественных функций, таких как \(+\), \(-\), \(\times\), \(/\), \(\sqrt{\quad}\), и так далее. Не вдаваясь в подробности, предположим, что каждая элементарная машинная операция создает результат с плавающей запятой, относительная погрешность которого ограничена \(\macheps\).
Например, если \(x\) и \(y\) находятся в \(\float\), то для машинного сложения \(\oplus\) мы имеем оценку 9{-16}\), что очень мало — не только в повседневном исчислении, но и по отношению к операндам, которые по модулю близки к 1. С другой стороны, разница столь же велика, как и сам точный результат! Мы формализуем и обобщим это наблюдение в следующем разделе. В то же время имейте в виду, что точность вычислений с плавающей запятой не может считаться само собой разумеющейся. Даже в идеале мы не должны ожидать, что два математически эквивалентных результата будут равны, а только то, что они будут относительно близки друг к другу.
✍ Рассмотрим множество с плавающей запятой \(\float\), определяемое (1) и (2) с \(d=4\).
(a) Сколько элементов \(\float\) есть в действительном интервале \([1/2,4]\), включая конечные точки?
(b) Какой элемент \(\float\) ближе всего к действительному числу \(1/10\)?
(c) Какое наименьшее натуральное число не входит в \(\float\)?
✍ Докажите, что (3) эквивалентно (4).
(Это означает сначала показать, что из (3) следует (4), а затем отдельно, что из (4) следует (3).)
⌨ Существуют гораздо лучшие рациональные приближения к \(\pi\), чем \(22/7\). Для каждого из приведенных ниже найдите его абсолютную и относительную точность и (округлив до целого числа) количество точных цифр. (В Julia переменная pi по умолчанию настроена на приближение с плавающей запятой к \(\pi\).)
(а) 355/113
(б) 103638/32989
✍ IEEE 754 одинарная точность указывает, что 23 двоичных бита используются для мантиссы \(f\) в (2). Поскольку они требуют меньше места для хранения и могут работать быстрее, чем значения двойной точности, значения одинарной точности могут быть полезны в приложениях с низкой точностью.
(a) В десятичной системе счисления какое первое число одинарной точности больше \(1\) в этой системе?
(b) Какое наименьшее положительное целое число не является числом одинарной точности?
⌨ Джулия определяет функцию nextfloat , которая возвращает следующее большее значение заданного числа с плавающей запятой.
2}{2n}=1.\] 94\):
r = randn(10000) # рисуем случайные числа х = сумма (знак (z) для z в r)
Выполнить миллион случайных обходов, вычислив средние значения \(x_{10000}\) и \(|x_{10000}|\). Сравните их с \(\alpha_n=0\) и \(\beta_n\приблизительно \sqrt{2n/\pi}\) в \(n=10000\).
Термины «машинный эпсилон», «машинная точность» и «округление единиц» не используются последовательно в ссылках, но для наших целей различия незначительны.
На самом деле, есть несколько еще меньших денормализованных чисел, которые имеют меньшую точность, но мы не будем использовать этот уровень детализации.
ВЕБ-САЙТ FABIEN SANGLARD
29 августа 2017 г.
Визуальное объяснение операций с плавающей запятой
Возможно, рисунок, так как они, кажется, лучше проходят через мой мозг.Я закончил с тем, что следует, и я решил включить его в книгу. Я не утверждаю, что это мое изобретение, но я никогда не видел, чтобы плавающие точки объяснялись таким образом. Я надеюсь, что это поможет нескольким людям вроде меня, у которых немного аллергия на математические обозначения.
Как обычно объясняют числа с плавающей запятой
В языке C плавает представляют собой 32-битный контейнер, соответствующий стандарту IEEE 754. Их назначение – хранить и позволять операции по приближению действительных чисел. То, как я видел их объяснение до сих пор, выглядит следующим образом. 32 бита разделены на три части: 9{(E-127)} $$
Как все ненавидят числа с плавающей запятой, когда им объясняют. Обычно я переворачиваю стол. Может быть, у меня аллергия на математическую нотацию, но что-то просто не щелкает, когда я это читаю. Такое ощущение, что учишься
нарисовать сову.
Многие считают арифметику с плавающей запятой эзотерической темой.— Дэвид Голдберг
Другой способ объяснить…
Хотя это правильно, такой способ объяснения плавающей запятой оставляет некоторых из нас совершенно непонятными. невежественный. К счастью, есть другой способ объяснить это. Вместо экспоненты подумайте Окна между двумя последовательными степенями двух целых чисел. Вместо мантиссы подумайте смещения в этом окне. 9{23} = 8388608 $ ведер. С окном и смещением вы можете аппроксимировать число. Окно – отличный механизм для защиты от перелива. Как только вы достигли максимума в окне (например, [2,4]), вы можете «переместить» его вправо и представить число в следующем окне (например, [4,8]). Это стоит лишь немного точности, так как окно становится вдвое больше.
На следующем рисунке показано, как будет закодировано число 6.1. Окно должно начинаться с 4 и простираться до следующей степени двойки, равной 8.