Интересно, как правильно инвертировать этот расчет:
float x = a * 25.0f + b; // where a and b are integers and b is in [0-25[
Как я могу избежать возможных ошибок округления с плавающей точкой. Ответы очевидны, даже если x имеет некоторую ошибку, поэтому это должно быть возможно реализовать.
Попробуйте использовать арифметика по модулю, то есть целочисленное деление /
и остаток %
:
int a = ((int) (x + 0.5f)) / 25;
int b = ((int) (x + 0.5f)) % 25;
если x
могу иметь ошибки округления, например x = 53.999997
вместо 54
затем круглый это до ближайшего целого числа: (int) (x + 0.5f)
, Пожалуйста, обратите внимание, что x
должно быть достаточно мал быть брошенным в int
: x = 1e30f
определенно потерпит неудачу.
Для диапазона а вы дали, вы не можете безопасно вернуть б.
Для = 10 ^ 6 вам нужно 20 бит. Если вы умножите на 25, вам нужно еще 5 бит. Таким образом, для экстремальных значений a вам понадобится 25 битов значений и для представления x. IEEE 754 с плавающей запятой одинарной точности предлагает только вам 24. Это означает, что x может потерять младший значащий бит. Вместо истинного значения x у вас есть x +/- 1.
Но у вас есть доступ к дополнительной информации:
((int)(x))%4 == 2
тогда вы знаете, что не было никакого округления. Действительно, отмена последнего бита является случаем точного связывания и приводит к округлению до ближайшего, даже в режиме округления по умолчанию IEEE 754.Вывод: здесь вы должны использовать двойную точность