-1

Вот вычитаниемIEEE754 поплавок точка точность теряется вычитание

Первый номер

Decimal  3.0000002 
Hexadecimal 0x4040001 
Binary: Sign[0], Exponent[1000_0000], Mantissa[100_0000_0000_0000_0000_0001] 

второй номер вычесть:

Decimal 3.000000 
Hexadecimal 0x4040000 
Binary: Sign[0], Exponent[1000_0000], Mantissa[100_0000_0000_0000_0000_0000] 

============= =============================

в этой ситуации показатель уже же, нам просто нужно вычитать мантиссы , В IEEE754 мы знаем, что перед мантиссой есть укрытие 1. Таким образом, результат мантисса должна быть:

Mantissa_1[1100_0000_0000_0000_0000_0001] - Mantissa_2[1100_0000_0000_0000_0000_0000] 

который равен

Mantissa_Rst = [0000_0000_0000_0000_0000_0001] 

Но это число не нормируется, из-за первый тайник бит не равен 1. Таким образом, мы сдвигать Mantissa_Rst право 23 раза , и экспоненциальные минусы 23 одновременно.

Тогда мы имеем значение результата Всего

Hexadecimal 0x4040000 

Binary: Sign[0], Exponent[0110_1000], Mantissa[000_0000_0000_0000_0000_0000]. 

32 бит, без округления необходимо.

Обратите внимание, что в регионе мантиссы, есть еще скрытый 1.

Если мои расчеты верны, то преобразование результат в десятичном числе +0,00000023841858, по сравнению с реальным результатом 0,0000002, я до сих пор считаю, что это не очень точный.

Итак, вопрос в том, что мои расчеты ошибочны? или на самом деле это реальная ситуация и происходит все время в компьютере?

+2

Десятичное число '3.0000002' не может быть точно представлено в базе 2, оно будет округлено до ближайшего представимого числа. Преобразуйте его в двойную точность и выведите больше цифр, вы увидите, что я имею в виду. –

+0

Это происходит постоянно на компьютере. если вы хотите это увидеть. Попробуйте вычислить (1/3 + 1/3 +1/3) == 1. потому что это может быть точно 0,0000002 с 23 для мантиса и 8 для экспонента – Alon

+0

Если вы считаете, что это плохо, поймите, что это _benign_ аннулирование. Существует аналогичная проблема, известная как _catastrophic_ аннулирование. – MSalters

ответ

4

Неточность уже начинается с ввода. 3.0000002 - это доля с главным коэффициентом в пять в знаменателе, поэтому ее «десятичное» разложение в базе 2 является периодическим. Нет достаточного количества бит мантиссы, чтобы точно представлять его. Поплавок, который вы даете, фактически имеет значение 3.0000002384185791015625 (этот -). Да, это происходит все время.

Не отчаивайтесь! База 10 имеет ту же проблему (например, 1/3). Это не проблема. Ну, это для некоторых людей, но, к счастью, есть другие типы номеров, доступные для их нужд. Числа с плавающей запятой имеют много преимуществ, и небольшая ошибка округления не имеет значения для многих приложений, например, когда даже ваши входы - это абсолютно точные измерения того, что вас интересует (много научных вычислений и моделирования). Также помните, что 64-битные поплавки также существуют. Кроме того, ошибка ограничена: при наилучшем округлении результат будет в пределах 0,5 единиц на последнем месте удален из результата с бесконечной точностью. Для 32-битного поплавка величины в качестве вашего примера это примерно 2^-25 или 3 * 10^-8. Это становится все хуже и хуже, так как вы выполняете дополнительные операции, которые должны быть округлены, но с тщательным цифровым анализом и right algorithms вы можете получить много средств из них.

+0

Итак, были ли правильные шаги по вычислению руки? Я имею в виду, что со скрытым 1 я не очень уверен в способах моих шагов вычисления. –

+0

@ShuaiyuJiang Я не слишком внимательно смотрел на ваши шестнадцатеричные вычисления, но я не видел ничего плохого с ними. –

+0

@ShuaiyuJiang Я не переделал расчеты, сколько стоит сдвинуть, что такое новый экспонент, и т. Д., Но в большой картине он выглядит правильно. – delnan

1

Всякий раз, когда x/2 ≤ y ≤ 2x, расчет x - y равен точный, что означает, что ошибки округления вообще нет.Это также имеет место в вашем примере.

Вы просто ошиблись в предположении, что вы можете иметь число с плавающей запятой, равное 3.0000002. Вы не можете. Тип «float» может представлять только целые числа менее 2^24, умноженные на две. 3.0000002 не является таким числом, поэтому округляется до ближайшего числа с плавающей запятой, которое ближе к 3.00000023841858. Вычитание 3 точно вычисляет разницу и дает результат, близкий к 0,00000023841858.