为什么相同数字的 sin 返回两个截然不同的值?

问题描述

有人能解释为什么这两个输出有很大不同吗?

当我打印出 (float)direction*PI/180.0ftheta 时,它们都按预期计算为 1.5708。为什么在将其放入 sin 函数之前将其放入浮点变量会使输出产生如此巨大的差异?另请注意,test2 返回正确答案 (1),而 test 返回错误答案 (0)。

#include <iostream>
#include <cmath>

#define PI 3.14159265


int main()
{   
    int direction = 90;
    float theta = (float)direction*PI/180.0f;
    int test =  (int)sin(theta);
    int test2 = (int)sin((float)direction*PI/180.0f);
    
    std::cout << theta << " " << (float)direction*PI/180.0f << " " << test << " " << test2;
}

解决方法

(float)direction*PI/180.0f 使用 double 算术。 PI 是一个 double 文字,因为它没有 f 后缀。其他两个操作数((float)direction180.0f)是 float,是的,但它们只是被提升为 double(并且转换在 IEEE 浮点中是精确的)。请注意,由于运算符优先级,(float) 仅适用于 direction。对于 test2,您将结果 double 直接传递给 sin,而 sin 正好返回 1。对于 test,您首先将分配中的 double 向下转换为 floattheta,然后将其重新转换为 double 以调用sin(请注意,您调用的是 C 的 double sin(double),而不是 C++ 的 float std::sin(float))。通过强制转换,theta 失去了一点四舍五入的价值。 sin 然后相应地给出一个小于 1 的值,当转换为 0 时,它会一直舍入到 int。如果您调用了 std::sin,那么您将得到 1,因为 std::sin 会将略小于 1 double 的值四舍五入为 float ,这将给出 1(与截断为 int 不同)。

像这样将浮点值打印到 std::cout 对调试浮点数没有用,因为值会四舍五入。我喜欢使用 std::hexfloat,它显示 real 二进制值(转换为十六进制),而不是十进制谎言。我还摆脱了 PI 并将 C 风格的强制转换为函数风格的强制转换,以更清楚地显示正在发生的事情。我已将 testtest2 转换为 doublesin 的返回类型),以便我们可以真正了解它们。

int main() {
    int direction = 90;
    float theta = float(direction)*3.14159265/180.0f;
    double test1 = sin(theta);
    double test2 = sin(float(direction)*3.14159265/180.0f);
    std::cout << std::hexfloat;
    std::cout << theta << " " << float(direction)*3.14159265/180.0f << "\n";
    std::cout << test1 << " " << test2 << "\n";
}

Godbolt

它给了

0x1.921fb6p+0 0x1.921fb53c8d4fp+0
0x1.ffffffffffff7p-1 0x1p+0

这清楚地向我们展示了我们在 test2 中使用的值的位数比 theta 多,因为它是 doublefloat theta。您还看到 test1 几乎是 1,但不完全是。

,

舍入错误。 您的测试变量 = 1.0。 I C 和 C++,0.9999999999999 被四舍五入为 0。

#include <iostream>
#include <cmath>

#define PI 3.14159265


int main()
{   
    int direction = 90;
    float theta = (float)direction*PI/180.0f;
    auto test =  sin(theta);
    auto test2 = sin((float)direction*PI/180.0f);
    
    std::cout << theta << " " << (float)direction*PI/180.0f << " " << (int) test << " " << (int) test2 << std::endl;
    std::cout <<std::boolalpha << "test >= 1.0 = " << (test >= 1.0) << std::endl;
    std::cout << "test2 >= 1.0 = " << (test2 >= 1.0) << std::endl;
    std::cout << "test == test2 = " << (test == test2) << std::endl;
    std::cout << "test < test2 = " << (test < test2) << std::endl;
}

输出:

1.5708 1.5708 0 1
test >= 1.0 = false
test2 >= 1.0 = true
test == test2 = false
test < test2 = true