То, что это работает, совсем не тривиально! Это свойство представления IEEE с плавающей точкой, что int∘floor = ⌊⋅⌋, если величина рассматриваемых чисел достаточно мала, но возможны разные представления, где int (floor (2.3)) может быть 1.
Этот пост объясняет, почему он работает в этом диапазоне .
В двойном выражении вы можете без проблем представлять 32-битные целые числа. Там не может быть никаких вопросов округления. Точнее, double может представлять все целые числа от 2 53 до -2 53 включительно. .
Краткое объяснение : двойной может хранить до 53 двоичных цифр. Когда вам требуется больше, число дополняется нулями справа.
Отсюда следует, что 53 единицы - это наибольшее число, которое можно хранить без заполнения. Естественно, все (целые) числа, требующие меньше цифр, могут быть сохранены точно.
Добавление одного к 111 (опущено) 111 (53) приводит к 100 ... 000, (53 нуля). Как мы знаем, мы можем хранить 53 цифры, что делает заполнение нуля самым правым.
Отсюда 2 53 .
Более подробно: нам нужно рассмотреть, как работает IEEE-754 с плавающей запятой.
1 bit 11 / 8 52 / 23 # bits double/single precision
[ sign | exponent | mantissa ]
Затем число рассчитывается следующим образом (за исключением особых случаев, которые здесь не имеют значения):
-1 знак × 1.Мантисса × 2 Показатель степени - смещение
где смещение = 2 экспонента - 1 - 1 , то есть 1023 и 127 для двойной / одинарной точности соответственно.
Зная, что умножение на 2 X просто сдвигает все биты X влево, легко видеть, что любое целое число должно иметь все биты в мантиссе, которые заканчиваются справа от десятичной точки до нуля.
Любое целое число, кроме нуля, имеет следующую форму в двоичном виде:
1x ... x, где x -es представляют биты справа от MSB (самый старший бит).
Поскольку мы исключили ноль, всегда будет единица MSB, поэтому она не сохраняется. Чтобы сохранить целое число, мы должны привести его в вышеупомянутую форму: -1 знак × 1.Mantissa × 2 экспонента - смещение .
Это то же самое, что сдвигать биты над десятичной точкой, пока слева от MSB не будет только MSB. Все биты справа от десятичной точки затем сохраняются в мантиссе.
Отсюда видно, что мы можем хранить не более 52 двоичных цифр, кроме MSB.
Отсюда следует, что наибольшее число, в котором все биты хранятся явно
111(omitted)111. that's 53 ones (52 + implicit 1) in the case of doubles.
Для этого нам нужно установить показатель степени так, чтобы десятичная точка была смещена на 52 позиции. Если бы мы увеличили показатель степени на единицу, мы не смогли бы узнать цифру справа налево после десятичной точки.
111(omitted)111x.
По соглашению, это 0. Установив всю мантиссу на ноль, мы получим следующее число:
100(omitted)00x. = 100(omitted)000.
Это 1 с последующими 53 нулями, 52 сохраненными и 1 добавленными из-за показателя степени.
Это представляет 2 53 , который отмечает границу (и отрицательную и положительную), между которой мы можем точно представить все целые числа. Если бы мы хотели добавить один к 2 53 , мы должны были бы установить неявный ноль (обозначенный как x
) на один, но это невозможно.
math.floor
возвращает число с плавающей запятой в v2.6 , но оно возвращает целое число в v3 . На данный момент (почти через шесть лет после ОП) эта проблема может появляться редко.