gpt4 book ai didi

c++ - 不同的编译器用来处理数字转换溢出的一些常见策略是什么?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:14:15 24 4
gpt4 key购买 nike

我明白,在 C++ 中,当我将 float/double 转换为 int 时, float 超出int 可以容纳的范围,结果未定义为 C++ 语言的一部分。结果取决于实现/编译器。 常见的编译器使用哪些策略来处理这个问题?

7.2E12 转换为 int 可以产生值 16348119042147483647。例如,有人知道编译器在每种情况下都在做什么吗?

最佳答案

编译器生成指令序列,为所有不会导致溢出的输入生成正确的结果。这就是它所需要担心的(因为 overflow in the conversion from floating-point to integer is undefined behavior )。 编译器不会“处理”溢出,而是完全忽略它们。如果平台上的底层汇编指令引发异常,没问题。如果他们环绕,很好。如果它们产生荒谬的结果,那也没关系。


例如,常量表达式可能会在编译时使用不同于平台上生成的汇编指令行为的规则转换为整数。我的博文给出了例子:

int printf(const char *, ...);

volatile double v = 0;

int main()
{
int i1 = 2147483648.0;
int i2 = 2147483648.0 + v;
printf("%d %d\n", i1, i2);
}

它生成一个程序,为 i1i2 打印两个不同的值。这是因为 i1 计算中的转换是在编译时应用的,而 i2 计算中的转换是在运行时应用的。


作为另一个例子,在 x86-64 平台上从 double 到 32 位 unsigned int 的转换的特定情况下,结果可能很有趣:

x86 指令集中没有将 float 转换为无符号整数的指令。

在 Mac OS X for Intel 上,编译一个 64 位程序,从 double 到 32 位 unsigned int 的转换被编译在一条指令中:64 位转换指令,cvttsd2siq , 目标是一个 64 位寄存器,其中只有底部的 32 位随后将用作它表示的 32 位无符号整数:

$ cat t.c
#include <stdio.h>
#include <stdlib.h>
int main(int c, char **v)
{
unsigned int i = 4294967296.0 + strtod(v[1], 0);
printf("%u\n", i);
}
$ gcc -m64 -S -std=c99 -O t.c && cat t.s

addsd LCPI1_0(%rip), %xmm0 ; this is the + from the C program
cvttsd2siq %xmm0, %rsi ; one-instruction conversion

这解释了在该平台上,如何为足够小的 double (特别是小到足以放入带符号的 64 位整数)获得模 232 的结果。

在旧的 IA-32 指令集中,没有将 double 转换为 64 位有符号整数的指令(也没有将 double 转换的指令> 为 32 位 unsigned int 之一)。到 32 位 unsigned int 的转换必须通过组合一些确实存在的指令来完成,包括两条指令 cvttsd2si 以将 double 转换为 32 位有符号整数:

$ gcc -m32 -S -std=c99 -O t.c && cat t.s…addsd LCPI1_0-L1$pb(%esi), %xmm0 ; this is the + from the C programmovsd LCPI1_1-L1$pb(%esi), %xmm1 ; conversion to unsigned int starts heremovapd %xmm0, %xmm2subsd %xmm1, %xmm2cvttsd2si %xmm2, %eaxxorl $-2147483648, %eaxucomisd %xmm1, %xmm0cvttsd2si %xmm0, %edxcmovael %eax, %edx…

Two alternative solutions are computed, respectively in %eax and in %edx. The alternatives are each correct on different definition domains. If the number to convert, in %xmm0, is larger than the constant 231 in %xmm1, then one alternative is chosen, otherwise, the other one is. The high-level algorithm, using only conversions from double to int, would be:

if (d < 231)then (unsigned int)(int)delse (231 + (unsigned int)(int)(d - 231))

This translation of the C conversion from double to unsigned int gives the same saturating behavior as the 32-bit conversion instruction that it relies on:

$ gcc -m32 -std=c99 -O t.c && ./a.out 123456
0

关于c++ - 不同的编译器用来处理数字转换溢出的一些常见策略是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24505543/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com