испытать тебя,System.out.println(1.0f - 0.9f)
каков результат?
3...
2...
1...
Выявленный ответ: 0.100000024
Если вам интересно, почему ответ не 0,1, просто посмотрите вниз⬇️
Как числа с плавающей запятой представлены в информатике?
Все мы знаем, что в математике научная запись используется для аппроксимации очень большого или очень маленького числа с большим количеством цифр. Представление в научной нотации выглядит следующим образом:
a x 10^n, где 1 ⩽ |a| ⩽ 10, a называется有效数字
При отображении научных обозначений в математическом мире в числа с плавающей запятой в компьютерном мире, принимая во внимание реализацию аппаратных устройств памяти и изменение системы счисления (с десятичной на двоичную), форма немного отличается.
Среди них показатель степени в десятичной системе стал «кодом порядка», значащее число было изменено на «мантисса», а бит уникального знака в компьютерной двоичной системе счисления составляет три элемента в методе компьютерной научной записи. :
- знаковый бит
- экспонента
- мантисса
Это может показаться недостаточно интуитивным. Возьмем в качестве примера число одинарной точности с плавающей запятой. Оно занимает 4 байта и всего 32 бита. Три элемента следующие:
Давайте пройдемся по ним один за другим:
-
знаковый бит
Занимает старший двоичный бит, 0 для положительных чисел и 1 для отрицательных чисел.
-
экспонента
8 бит справа от бита знака используются для представления экспоненты.Прежде всего, дайте понять, что в мейнстриме компьютерного мира
IEEE754
В стандарте показатель степени хранится в показателе степени, соответствующем показателю степени.移码
.Согласно Википедии для
移码
Определение:Сдвиг кода (также называемый инкрементным кодом) — это инверсия знакового бита.дополнять, что обычно делается путем вычитания 1 из кода сдвига показателя степеничисло с плавающей запятойизкод заказа, целью введения является обеспечение числа с плавающей запятойнулевая машинадля всех 0s.
Получить [X] shift = x + 2^n-1 (n — двоичная цифра x, включая позицию знака, в представлении кода заказа, n = 8)
-
мантисса
Как упоминалось выше, биты мантиссы представляют собой значащие цифры числа с плавающей запятой. Старший бит нормализованной мантиссы должен быть равен 1 (вы пробуете, тщательно пробуете...), поэтому в целях экономии места для хранения этот старший бит 1 опущен. Следовательно, мантисса, фактически занимаемая битами мантиссы, составляет 24 бита, а показано 23 бита.
После введения трех элементов давайте возьмем несколько простых примеров, чтобы подробно проиллюстрировать вышеизложенные знания, например, представление десятичного числа «8,0» в компьютерном мире:
Увидев это, вы легко узнаете:
Тогда я проверю вас, как представить десятичное число «0,9»?
Раскройте ответ:
Этот пример просто для того, чтобы показать вам:
某些浮点数无法在有限的二进制科学计数法中精确表示。
Сложение и вычитание чисел с плавающей запятой
Позвольте вас спросить, как мы складывали и вычитали десятичные дроби, когда учились в начальной школе (положив слона в холодильник, он разбит на несколько шагов)?
1. Чтобы вычислить десятичное сложение и вычитание, сначала выровняйте десятичные точки каждого числа (то есть выровняйте числа по одной и той же цифре)
2. Вычислите по правилам целочисленного сложения и вычитания и, наконец, выровняйте десятичную точку на горизонтальной черте в числе.
Из вышеизложенного нетрудно увидеть, что наиболее важным шагом в десятичном сложении и вычитании являетсявыравнивание десятичной точки. Точно так же для сложения и вычитания чисел с плавающей запятой «выравнивание десятичной точки» также является очень важной ссылкой. Сопоставление с вычислениями с плавающей запятой в экспоненциальном представлении должно гарантировать, чтотот же индекс, этот шаг имеет профессиональный термин, называемыйРабота в обратном порядке:
Сначала найдите два числа с плавающей запятойкод заказаРазность ⊿E=Ex-Ey, добавить ⊿E к коду младшего разряда, чтобы сделать его равным коду старшего разряда, и сдвинуть вправо мантисса числа с плавающей запятой, соответствующего коду младшего порядка на соответствующее количество цифр, чтобы гарантировать, что значение числа с плавающей запятой не изменится.
- Принцип сопоставления порядка заключается в том, что меньший порядок соответствует большому порядку. Причина этого в том, что если большой порядок соответствует меньшему порядку, старший порядок числовой части мантиссы должен быть сдвинут наружу, и меньший порядок смещается в большой порядок Младший порядок числовой части мантиссы, Таким образом, потеря точности меньше.
- Если ⊿E=0, это означает, что порядковые коды двух чисел с плавающей запятой уже одинаковы, и нет необходимости выполнять операцию «по порядку».
Перед выполнением операции «от заказа к заказу» сначала проверяется, имеют ли два числа, участвующих в операции, значение 0. Поскольку операции с числами с плавающей запятой очень сложны, в Google«Советы по производительности»Также есть совет:
Avoid using floating-point
Когда одно из чисел равно 0, другое значение, участвующее в вычислении, будет непосредственно возвращено как результат.
После завершения операции порядка выполните соответствующую операцию над мантиссом (прибавьте непосредственно к сумме, если это отрицательное число, сначала преобразуйте его в дополнение, а затем выполните операцию суммирования), которая аналогична десятичной операции.
Если результат, полученный в результате вышеперечисленных шагов, по-прежнему удовлетворяет
a x 2^n.Если 1 ⩽ |a| ⩽ 2, обработка не требуется, если не выполняется,Необходимо переместить количество цифр мантиссы (влево или вправо), чтобы она соответствовала этой форме. Этот шаг также потеряет точность. Этот шаг называется нормализацией результата. Перемещение мантиссы вправо называется правильным правилом, а движение влево называется левым правилом.
компенсироватьПотеря точности в операции «от заказа к заказу» и в процессе нормализации результатов приведет к сохранению удаленной части данных, которая保护位
, дождитесь нормализации результата перед округлением в соответствии с защитными битами.
Подводя итог, процесс выглядит примерно так:
После разъяснения вышеизложенных понятий давайте изучим вопросы, поднятые следующим заголовком:
1 - 0,9 ≠ 0,1, почему так?
Почему 1-0,9 не равно 0,1?
Прежде всего, нам должно быть ясно, что вычитание в компьютерах часто преобразуется в сложение для операции. Например, 1,0 - 0,9 эквивалентно 1,0 + (-0,9).
Сначала выпишем двоичную кодировку 1.0 и -0.9:
написано выше,Старший бит мантиссы скрывает 1 (если не помните, подумайте над этим), поэтому фактическая мантисса 1.0:
1000 - 0000 - 0000 - 0000 - 0000 - 0000
Фактическая мантисса -0,9:
1110 - 0110 - 0110 - 0110 - 0110 - 0110
Далее следуемОбнаружение нулевого значения -> Двоичная операция -> Сумма мантиссы -> Нормализация результата -> Округление результатаДавай сделаем это:
Обнаружение нулевого значения
Очевидно, что размер обоих чисел не равен 0, этот шаг пропускается.
Работа в обратном порядке
Код заказа 1.0 равен 127, а код заказа -0.9 равен 126. Для сравнения мы можем найти, чтоДополнение мантиссы -0,9 необходимо переместить вправо, а старший бит заполнить 1, чтобы показатель степени стал 127, и был достигнут «эффект выравнивания десятичной точки»., дополнение битов мантиссы, сдвинутых на -0,9, равно:
1000 - 1100 - 1100 - 1100 -1100 - 1101
сумма мантиссы
Преобразуйте мантиссы 1,0 и -0,9 в дополнение до единицы, затем добавьте их побитово (После завершения операции ордера бит ордера больше не участвует в операции, в операции участвуют только бит мантиссы и бит знака):
Результат операции по получению мантиссы:
0000 - 1100 - 1100 - 1100 - 1100 -1101
нормализация результата
Операция после суммы мантисс неудовлетворительна (Старший бит мантиссы должен быть равен 1. Если вы не понимаете, почему, вы также должны подумать об этом.), поэтому здесь нам нужно сдвинуть результат влево на 4 бита и вычесть 4 из показателя степени.结果规格化
.
После такой операции показатель степени равен 123 (соответствующий двоичный код равен 1111011), а мантисса равна
1100 - 1100 - 1100 - 1100 - 1101 - 0000
Затем скройте старший бит своей мантиссы, а затем станьте:
100 - 1100 - 1100 - 1100 - 1101 - 0000
Окончательные результаты
Наконец, результат операции 1.0 - 0.9:
Наконец, мы получаем бит знака 0, показатель степени 01111011 и мантиссу 100 - 1100 - 1100 - 1100 - 1101 - 0000, и соответствующее десятичное представление равно 0,100000024.
Нежелательные последствия потери точности
Поскольку существует проблема потери точности при использовании чисел с плавающей запятой, какое влияние это окажет на нашу повседневную разработку?
Непредсказуемое поведение часто возникает при использовании оценки размера с плавающей запятой для управления определенными бизнес-процессами.
Представьте себе такой сценарий: при отправке заказа приложение электронной коммерции должно проверить, достаточно ли средств на балансе пользователя для оплаты заказа. Если этого недостаточно, кнопка отправки заказа отключена.
Не понимая потери точности, мы можем легко записать это суждение:
btSubmit.setEnabled(balance >= orderAmount)
Если в это время баланс или сумма заказа теряют точность, может случиться так, что баланса пользователя явно достаточно для оплаты заказа, но пользователь не может отправить заказ, потому что неправильное решение внешнего интерфейса отключает кнопку для отправки заказа (Не спрашивайте меня, откуда я знаю такую детальную сцену, спросите о самоубийстве).
Как избежать нежелательных последствий потери точности?
Избегайте ненужного использования чисел с плавающей запятой.
Использование чисел с плавающей запятой сопряжено со следующими проблемами: снижение производительности и снижение точности. В целом числа с плавающей запятой примерно в 2 раза медленнее, чем целые числа на устройствах Android. Поэтому, если использование для параметра типа с плавающей запятой не является неизбежным, рекомендуется использовать целочисленный тип вместо типа с плавающей запятой.
Используйте числа с плавающей запятой двойной точности, когда нельзя избежать чисел с плавающей запятой
double
заменитьfloat
.
Во-первых, по скорости,float
иdouble
Разницы в нынешнем железе нет.В решении времени и пространства я полагаю, что большинство людей более склонны использовать пространство вместо времени. В то же время, благодаря большему объему памяти, точность типа с плавающей запятой двойной точности намного выше, чем у типа с плавающей запятой одинарной точности.
Например, в примере, упомянутом в предыдущем разделе, мы можем полностью использовать центы в людях в качестве единицы измерения, а баланс и сумму заказа преобразовать в целочисленные сравнения в центах, чтобы избежать непредсказуемых неблагоприятных последствий, вызванных потерей точности.
Суммировать
Подводя итог, мы не можем избежать потери точности чисел с плавающей запятой в компьютере, но мы можем разумно избежать неблагоприятных последствий, вызванных потерей точности, например, избежать использования размера двух чисел с плавающей запятой в качестве суждения. основе управления бизнес-процессами.