在下面的代码中:
#include <cstdint>
#include <cinttypes>
#include <cstdio>
using namespace std;
int main() {
double xd = 1.18;
int64_t xi = 1000000000;
int64_t res1 = (double)(xi * xd);
double d = xi * xd;
int64_t res2 = d;
printf("%" PRId64"\n", res1);
printf("%" PRId64"\n", res2);
}
使用针对 32 位 Windows 的 v4.9.3 g++ -std=c++14
我得到了输出:
1179999999
1180000000
这些值可以不同吗?
我预计,即使编译器使用比 double
更高的内部精度来计算 xi * xd
,它也应该始终如一地执行此操作。浮点转换中的精度损失是实现定义的,并且此计算的精度也是实现定义的 - [c.limits]/3 表示 FLT_EVAL_METHOD
应该从 C99 导入。 IOW 我预计不应允许在一行上对 xi * xd
使用与在另一行上不同的精度。
注意:这是故意的 C++ 问题而不是 C 问题 - 我相信这两种语言在这方面有不同的规则。
最佳答案
even if the compiler uses a higher internal precision than double for the computation of xi * xd, it should do this consistently
无论是否需要(下面讨论),这显然不会发生:Stackoverflow 充斥着来自那些看到类似计算的人的问题,这些计算没有表面上的原因在同一个程序中 .
C++ 标准草案 n3690 说(强调我的):
The values of the floating operands and the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby.62
62) The cast and assignment operators must still perform their specific conversions as described in 5.4, 5.2.9 and 5.17.
所以 - 与 M.M. 的评论一致,与我之前的编辑相反 - 这是带有 (double)
的版本必须舍入为 64 位 double
的强制转换- 在问题中记录的运行中显然恰好 >= 1180000000 - 在截断为整数之前。没有 62) 的更一般情况使编译器可以自由地在其他情况下不提前舍入。
[c.limits]/3 says that FLT_EVAL_METHOD should be imported from C99. IOW I expected that it should not be allowed to use a different precision for xi * xd on one line than it does on another line.
检查 cppreference page :
Regardless of the value of FLT_EVAL_METHOD, any floating-point expression may be contracted, that is, calculated as if all intermediate results have infinite range and precision (unless #pragma STDC FP_CONTRACT is off)
正如 tmyklebu 评论的那样,它继续:
Cast and assignment strip away any extraneous range and precision: this models the action of storing a value from an extended-precision FPU register into a standard-sized memory location.
这最后与标准的“62)”部分一致。
评论:
STDC FP_CONTRACT does not seem to appear in the C++ Standard and also it's not clear to me exactly to what extent the C99 behaviour is 'imported'
没有出现在我看过的草稿中。这表明 C++ 不保证其可用性,保留上面提到的默认值 “任何浮点表达式都可以收缩”,但我们知道每个 M.M. (double)
上方的注释和标准和 cppreference 引用cast 是一个异常(exception),强制四舍五入到 64 位。
上面提到的 C++ 标准草案说 <cfloat>
:
The contents are the same as the Standard C library header . See also: ISO C 7.1.5, 5.2.4.2.2, 5.2.4.2.1.
如果需要其中一个 C 标准 STDC FP_CONTRACT
它更有可能被 C++ 程序移植使用,但我没有调查支持的实现。
关于c++ - C++ 标准是否允许这种浮点行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34389262/