What are some common strategies used by different compilers to handle overflow in numerical conversions?

I understand that in C ++, when I convert float/ doubleto int, as a result of which the floating point number is out of the range that can hold int, the result is not defined as part of the C ++ language. The result depends on the implementation / compiler. What strategies do common compilers use for this?

Converting 7.2E12to intmay result in 1634811904or 2147483647. For example, does anyone know what the compiler does in each of these cases?

+4
source share
1 answer

The compiler generates sequences of instructions that produce the correct result for all inputs that do not cause overflow. That's all there is to worry about (because overflow in floating point to integer conversions is undefined behavior ). The compiler does not "handle" overflows, as it completely ignores them . If the base assembly instructions (a) on the platform raise an exception, fine. If they turn around, great. If they produce meaningless results, again, fine.


, , . :

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);
}

, i1 i2. , i1 , i2 .


, double 32- unsigned int x86-64, :

x86 ​​ .

Mac OS X Intel, 64- , double-32- 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

, 2 32 , ( , , 64- ).

IA-32 double 64- ( double 32- unsigned int ). 32- unsigned int , , cvttsd2si 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 program
movsd LCPI1_1-L1$pb(%esi), %xmm1 ; conversion to unsigned int starts here
movapd %xmm0, %xmm2
subsd %xmm1, %xmm2
cvttsd2si %xmm2, %eax
xorl $-2147483648, %eax
ucomisd %xmm1, %xmm0
cvttsd2si %xmm0, %edx
cmovael %eax, %edx

%eax %edx. . %xmm0 , 2 31 %xmm1, , . , double int, :

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

C double unsigned int , 32- , :

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

Source: https://habr.com/ru/post/1546654/


All Articles