В документации cppreference указано, что std :: round будет специально округлять от нуля в «промежуточных случаях». Хотя это верно для литерала 0.5
, это не так для std::sin(pi/6)
. Я подумал, что это ошибка с плавающей запятой, поэтому напечатал значение, но оно точно 0.5
. Однако после проверки двоичного представления я вижу, что они действительно представлены по-другому. Я предоставил код, который использовал для этих проверок, ниже.
#include <iostream>
#include <stdio.h>
#include <cmath>
int main(int argc, char * argv[])
{
double const pi = std::acos(-1);
double const a = std::sin(pi/6);
double const b = 0.5;
std::cout << "round(" << a << ") = " << std::round(a) << "\n";
auto pa = reinterpret_cast<const unsigned char *>(&a);
auto pb = reinterpret_cast<const unsigned char *>(&b);
std::cout << "a = 0x";
for (size_t i = 0; i != sizeof(double); ++i) {
printf("%02x", pa[i]);
}
std::cout << "\nb = 0x";
for (size_t i = 0; i != sizeof(double); ++i) {
printf("%02x", pb[i]);
}
std::cout << "\n";
}
round(0.5) = 0
round(0.5) = 1
a = 0xffffffffffffdf3f
b = 0x000000000000e03f
Итак, мой вопрос, является ли это поведение округления частью спецификации C ++ или это ошибка? И в любом случае, есть ли какой-нибудь общий способ «исправить» представление значения, возвращаемого sin
? Я не уверен, в каком он формате, потому что, исходя из того, что я знаю о IEEE-754, похоже, что это должно быть NaN. Хотя, насколько я понимаю, c ++ не гарантирует представления с плавающей запятой IEEE-754?