我在一些浮点数学运算上遇到问题,我发现如果我在一行上进行数学运算,则会将-0传递给tan(),并且如果我在两行上进行运算,则会得到0传递给tan()。看看:
float theta = PI / 2.f;
float p = (PI / 2.f) - theta;
float result = tan(p);
上面的p = -0,结果= -4.37 ...
float theta = PI / 2.f;
float p = PI / 2.f;
p -= theta;
float result = tan(p);
上面的p = 0,结果= 0。
谁能解释其中的区别?我认为-0是由tan()导致的结果,尽管我在Google上找不到任何能解释原因的信息。为什么完全相同的计算跨不同的行会导致不同的答案?
谢谢
答案 0 :(得分:5)
可能是由于PI的类型。
如果您使用double
,它将更改为float,然后结果
就像您所代表的那样。
但是,如果PI为float
,则这两个测试方案都相等。
答案 1 :(得分:4)
@Naor所说的可能是正确的。但我想添加些东西。
您可能不会得到-4.37xx
,但会得到-4.37xxxe-xx
,这是一个很小的负数。
由于您总是会在浮点数学运算中出错。我说没有必要更改您的代码。两种剪裁都是正确的。
答案 2 :(得分:0)
所以我认为这是正在发生的事情
在两个示例中,PI都是一个定义,可能是这样定义的:
#define 3.14 //and some more digits
在C ++中,这样的数字被视为双精度数字。
预处理后,此表达式:
PI / 2.0f
将被视为双重类型的prvalue。这意味着该行隐藏了另一项操作:
float theta = PI / 2.f;
这是两次浮点转换,在这种情况下肯定会失去一些精度。
在第一个示例中,这也发生在这里:
float p = (PI / 2.f) - theta;
,但仅在评估整个表达式之后。请注意,在此求值过程中,(PI / 2.f)
仍将是双精度值,但是theta
将是浮点数到双精度转换值,这说明了与0.0的结果略有差异。
在最后一个示例中,您首先将(PI / 2.f)
转换为float:
float p = PI / 2.f;
在下一行从中减去浮点型theta
。哪一个结果必须为0.0,这可能还是编译器进行了优化; )。