Вопрос

После часа попыток найти ошибку в моем коде я наконец нашел причину.Я пытался добавить очень маленькое число с плавающей запятой к 1f, но ничего не произошло.Пытаясь понять, почему я обнаружил, что добавление этого небольшого числа с плавающей запятой к 0f работает отлично.

Почему это происходит?Имеет ли это отношение к «порядкам величины»?Есть ли какое-либо решение этой проблемы?

Заранее спасибо.

Редактировать:

Переход на двойную точность или десятичную дробь на данный момент невозможен.

Это было полезно?

Решение

Потому что точность для значения с плавающей запятой одинарной точности (32 бита) составляет около 7 цифр после десятичной точки.Это означает, что значение, которое вы добавляете, по сути равно нулю, по крайней мере, при добавлении к 1.Однако само значение можно легко сохранить в виде числа с плавающей запятой, поскольку в этом случае показатель степени мал.Но чтобы успешно добавить его в 1 нужно использовать показатель большего числа...и тогда цифры после нулей пропадают при округлении.

Вы можете использовать double если вам нужна большая точность.С точки зрения производительности это не должно иметь значения для современного оборудования, а память часто не настолько ограничена, чтобы вам приходилось думать о каждой отдельной переменной.

РЕДАКТИРОВАТЬ: Как вы заявили, используя double это не тот вариант, который вы могли бы использовать Суммирование Кахана, как акун отметил в комментарии.

Другим вариантом может быть выполнение промежуточных вычислений с двойной точностью и последующее приведение к float снова.Однако это поможет только в том случае, если операций будет больше, чем просто добавление очень маленького числа к большему.

Другие советы

Вероятно, это происходит потому, что количество разрядов точности в вещественном числе постоянно, но показатель степени, очевидно, может меняться.

Это означает, что, хотя вы можете прибавить свое маленькое число к 0, вы не можете ожидать, что оно будет добавлено к числу, показатель степени которого отличается от 0, поскольку в нем просто не останется достаточно цифр точности.

Вам следует прочитать Что должен знать каждый ученый-компьютерщик об арифметике с плавающей запятой.

Похоже, это как-то связано с точностью с плавающей запятой.На вашем месте я бы использовал другой тип, например decimal.Это должно исправить ошибки точности.

С float, вы получаете только точность около семи цифр.Таким образом, ваше число будет округлено до 1f.Если вы хотите сохранить такой номер, используйте double вместо

http://msdn.microsoft.com/en-us/library/ayazw934.aspx

В дополнение к принятому ответу: Если вам нужно суммировать множество небольших чисел и несколько больших, вам следует использовать Суммирование Кахана.

Если производительность является проблемой (поскольку вы не можете использовать double), затем двоичное масштабирование/фиксированная точка может быть вариант. floats хранятся как целые числа, но масштабируются на большое число (скажем, 2^16).Промежуточная арифметика выполняется с помощью (относительно быстрых) целочисленных операций.Окончательный ответ можно в конце преобразовать обратно в число с плавающей запятой, разделив на коэффициент масштабирования.

Это часто делается, если в целевом процессоре отсутствует аппаратный модуль вычислений с плавающей запятой.

Вы используете суффикс f в своих литералах, что делает эти числа плавающими, а не двойными.Таким образом, ваш очень маленький поплавок исчезнет в большом поплавке.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top