C++ C++;标准允许这种浮点行为吗?

C++ C++;标准允许这种浮点行为吗?,c++,floating-point,language-lawyer,c++14,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 res

在以下代码中:

#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);
}
这些值是否允许不同

我认为,即使编译器在计算
xi*xd
时使用的内部精度高于
double
,它也应该始终如一地这样做。浮动转换中的精度损失由实现定义,此计算的精度也由实现定义-[c.limits]/3表示应从C99导入
FLT\u EVAL\u方法。依我看,一行上的
xi*xd
的精度不应与另一行上的精度不同

注意:这是一个C++问题,而不是C问题——我相信这两种语言在这个领域有不同的规则。

即使编译器使用XI×XD计算的内部精度比双倍高,它也应该一致地执行<席/P> 无论是否需要(下文讨论),这显然不会发生:Stackoverflow充斥着人们提出的问题,这些人在同一个程序中看到类似的计算结果在没有表面原因的情况下发生变化

C++标准草案N3690(强调矿山):

浮点操作数的值和浮点表达式的结果可以以比类型要求更高的精度和范围表示;这些类型不会因此而改变。62

62)强制转换和赋值运算符仍必须按照5.4、5.2.9和5.17中所述执行其特定转换

因此,与M.M.的评论一致,与我之前的编辑相反,
(double)
强制转换的版本必须四舍五入到64位
double
,在截断为整数之前,显然在问题中记录的运行中,>=1180000000。更一般的情况是,在另一种情况下,编译器可以自由地不提前取整

[c.limits]/3表示应从C99导入FLT_EVAL_方法。我希望它不允许在一席上使用不同的精度,而不是在另一行上使用。 检查:

不管FLT_EVAL_方法的值是多少,任何浮点表达式都可以收缩,也就是说,计算时就好像所有中间结果的范围和精度都是无限的一样(除非禁用#pragma STDC FP_CONTRACT)

正如tmyklebu评论的那样,它继续:

强制转换和赋值去除任何无关的范围和精度:这模拟了将扩展精度FPU寄存器中的值存储到标准大小内存位置的操作

最后一部分与标准的“62”部分一致

M.M.评论:

STDC FPY合同似乎没有出现在C++标准中,而且我还不清楚C99行为是什么程度的“导入”< /P> 没有出现在我看的草稿中。这表明C++不保证其可用性,将上面提到的“任何浮点表达式都可能收缩”默认为“但是我们知道每M.My注释,并且在代码< >(double)< /Case> CAST之上的标准和CPULIST引号是一个异常,迫使舍入到64位。 <>上述C++标准草案中的<代码> <代码>:

内容与标准C库标题相同。 另见:ISO C 7.1.5、5.2.4.2.2、5.2.4.2.1


<>如果C++标准中有一个要求“代码> STDC FPY合同,它有更多的机会被C++程序使用,但是我没有调查支持的实现。

< P>根据FLTYEVALILY方法,席*XD可以比双倍的精度高。如果席是如此之大,以至于不能用双精度表示,那么我甚至不确定编译器是否允许将它精确地转换成long double或-不可能,因为转换发生在FLTYEVALILY方法覆盖的任何东西之前。不要求必须始终使用更高的精度

有两个地方必须转换为双精度:在转换点(双精度)和分配到双精度的点。有GCC版本,如果一个值已经“正式”了一倍(如XI*XD),即使在实际中它的精度更高,也可以将“双席”版本“优化”掉。“优化”总是一个错误,因为演员必须转换


因此,您可能会在未执行“转换为双精度”(cast to double)的情况下遇到此错误(如果该错误仍然存在),您可能会遇到不一致地使用更高精度的情况,如果FLT_EVAL_方法允许,这是合法的,如果FLT_EVAL_方法根本不允许,您甚至可能会遇到不一致地使用更高精度的情况,这将再次成为一个bug(不是不一致,而是首先使用更高的精度)

请注意,您需要将
xi*xd
计算为
long double
,并将
long double
转换为整数,以获得错误结果;1e9*1.18与1.18e9相比约为1/4 ulp。相关:标准的哪一行对应于该CPP参考线?CPP参考页显示在您引用的段落的正下方“强制转换和赋值去除任何无关的范围和精度:这模拟了将扩展精度FPU寄存器中的值存储到标准大小内存位置的操作。“这是在你所写的文件中出现的。<代码> STDC FPY合同似乎不出现在C++标准中,而且我还不清楚C99行为到底是什么程度‘进口’@ TMykLeBu:谢谢你指出这一点,这就使得CPUPACTION符合标准,我从上面查过和引用过。欢呼。@ M.M.同意 STDC FPY合同很难在C++标准的基础上进行推理。您可以尝试一下,看看您的编译器是否支持
1179999999
1180000000