Как я могу указать, в каком направлении округлить среднее значение двух поплавков, отличающихся LSB их значения?
Я работаю над рутиной оптимизации Нельдера-МИДа в C, которая включает в себя взятие среднего значения двух float
s. в редких (но вполне воспроизводимых) обстоятельствах эти два float
s, скажем x
и y
, отличаются только наименее значимым битом их значения. Когда берется среднее, ошибки округления подразумевают, что результат будет либо x
, либо y
.
Я хотел бы указать, что округление всегда должно быть в сторону второго float
. То есть я не могу просто указать, что округление должно быть к нулю или бесконечности, потому что я заранее не знаю, будет ли x
больше, чем y
.
(Как) я могу это сделать?
2 ответа:
Я не думаю, что для этого существует аппаратный режим округления. Тогда вы должны написать свою собственную функцию,
double average(double x, double y) { double a = 0.5*(x+y); return (a == x) ? y : a; }
Вы можете распознать частный случай и выбрать значение, которое хотите вернуть.
Интерес представляют следующие значения:
Когда значения имеют один и тот же знак и показатель степени и отличаются только на единицу в мантиссе.
Когда значения имеют один и тот же знак, экспоненты отличаются на единицу, и один из них с большим показателем имеет мантиссу 0, а другой-мантиссу, заполненную единицами.
Фактически, если вы используете номера IEEE-754 (что, вероятно, так и есть) вы можете выполнить оба теста сразу (после проверки таких вещей, как Zero, Inf и Nan):
if ( repr1 + 1 == repr2 || repr2 + 1 == repr1) ....
Причина этого в том, что экспонента помещается прямо рядом с мантиссой, и если мантисса-все единицы, то сложение продолжится в поле экспоненты.
Однако, говоря об этом, я бы предложил другую стратегию. Вместо того, чтобы просто возвращать второе число, вы можете проверить второй значимый бит и решить, хотите ли вы круг вверх или вниз. Таким образом, ошибки округления будут распределены равномерно.