2017-02-16 45 views
0
#include<iostream> 

long myround(float f) 
{ 
    if (f >= UINT_MAX) return f; 
    return f + 0.5f; 
} 

int main() 
{ 
    f = 8388609.0f; 
    std:cout.precision(16); 
    std::cout << myround(f) << std::endl; 
} 

Выхода: 8388610,0Поплавок округления ошибки

Я пытаюсь сделать чувство выхода. Следующее число с плавающей запятой больше 8388609.0 составляет 8388610. Но почему округленное значение не равно 8388609?

+1

_ «Следующее плавающее число больше 8388609,0 составляет 8388610» _ Как вы пришли к такому выводу? –

+0

Одиночные поплавки не имеют достаточного пространства, чтобы гарантировать представление всех этих десятичных цифр (более шести). Что вы пытаетесь сделать? –

+0

Этот код не компилируется. У вас нет объявления 'f'. Отправьте свой _actual_ [MCVE], который привел к заявленному выводу. –

ответ

1

IEEE-754 определяет несколько возможных режимов округления, но на практике почти всегда используется «круглый до ближайшего, привязывается к четному». Это также известно как «округление банкира», по какой-либо причине никто не может различить.

«Связывание с четным» означает, что если округленный результат вычисления с плавающей точкой находится точно на полпути между двумя представляемыми числами, округление будет в том направлении, которое делает LSB результата равным нулю. В вашем случае 8388609.5 находится на полпути между 8388609 и 8388610, но только последний имеет нуль в последнем бите, поэтому округление вверх. Если бы вы перешли в 8388610.0 вместо этого, результат будет округлен вниз; если бы вы прошли в 8388611.0, это было бы округлено вверх.

+0

Спасибо за ваше объяснение. Отвечает на мой вопрос. Кроме того, я предполагаю, что аппаратура с плавающей запятой делает это решение о том, как должно выполняться округление. Означает ли это, что аппаратное обеспечение FP фактически вычисляет точное значение и сопоставляет с представимым представлением с плавающей запятой на основе политики округления? – KodeWarrior

+0

Это ответ на мой вопрос о аппаратном обеспечении FP. http://pages.cs.wisc.edu/~markhill/cs354/Fall2008/notes/flpt.apprec.html – KodeWarrior

1

Если вы изменили свой пример на использование double, тогда ошибка исчезнет. Проблема в том, что float более ограничен, чем double в количестве значимых цифр, которые он может хранить. Добавление 0.5 к вашему значению просто превышает предел точности для поплавка, заставляя его преформировать некоторое округление. В этом случае 8388609.0f + 0.5f == 8388610.0f.

#include<iostream> 

long myround(double f) 
{ 
    if (f >= UINT_MAX) return f; 
    return f + 0.5; 
} 

int main() 
{ 
    double f = 8388609.0; 
    std::cout.precision(16); 
    std::cout << myround(f) << std::endl; 
} 

Если продолжать добавлять цифры на ваш номер, он также будет в конечном счете терпят неудачу по double.

Редактировать: Вы можете легко проверить это с помощью static_assert. Это компилируется на моей платформе static_assert(8388609.0f + 0.5f == 8388610.0f, "");. Скорее всего, он скомпилируется на вашем.