c++ - C++ 标准是否允许这种浮点行为?

标签 c++ floating-point language-lawyer c++14

在下面的代码中:

#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/

相关文章:

c++ - 为什么我可以在 C 中调用函数而不声明它,但不能在 C++ 中调用?

c++ - C++ 中变量的减号?

c++ - c 从 uint64 到 float64_IEEE 的转换?

c - 后缀表达式 (type-name){initializer-list}

c++ - 常量表达式中的模板化委托(delegate)复制构造函数

c++ - 如何从其他类型获取类型(C++ 模板元编程)

c++ - 对静态类成员的 undefined reference

c++ - x86 中不同数学函数的性能?

java - 360 度的正弦值非零

c++ - 缺少迭代器失效是否意味着推进迭代器的有效性?