将double转换为int?

将double转换为int?

问题描述:

我的代码如下:

int main(int argc, char *argv[])
{

    double f = 18.40;
    printf("%d\n", (int)(10 * f));

    return 0;
}

在VC6.0中结果为184,而在Codeblock中结果为183为什么?

The result is 184 in VC6.0, while the result in Codeblock is 183. Why?

原因是GCC试图使代码尽可能地与CPU的较早架构向后兼容。

The reason for this is that GCC tries to make the code backward compatible with older architectures of the CPU as much as possible, while MSVC tries to take advantage of the newer futures of the architecture.

MSVC生成的代码将两个数字相乘10.0×18.40:

The code generated by MSVC multiplies the two numbers, 10.0 × 18.40:

.text:00401006 fld     ds:dbl_40D168
.text:0040100C fstp    [ebp+var_8]
.text:0040100F fld     ds:dbl_40D160
.text:00401015 fmul    [ebp+var_8]
.text:00401018 call    __ftol2_sse

,然后调用名为 __ ftol2_sse 的函数,在该函数内部,它使用名为 cvttsd2si的指令将结果转换为整数

and then call a function named __ftol2_sse, inside this function it converts the result to integer using some instruction named cvttsd2si:

.text:00401189 push    ebp
.text:0040118A mov     ebp, esp
.text:0040118C sub     esp, 8
.text:0040118F and     esp, 0FFFFFFF8h
.text:00401192 fstp    [esp+0Ch+var_C]
.text:00401195 cvttsd2si eax, [esp+0Ch+var_C]
.text:0040119A leave
.text:0040119B retn

此指令, cvttsd2si ,是根据此页面

This instruction, cvttsd2si, is according to this page:


将标量双精度浮点值(带截断)转换为
到带符号的四字整数双字(SSE2)

Convert scalar double-precision floating-point value (with truncation) to signed doubleword of quadword integer (SSE2)

它基本上将double转换为整数。该指令是英特尔奔腾4引入的名为 SSE2 的指令集的一部分。

it basically converts the double into integer. This instruction is part of instruction set called SSE2 which is introduced with Intel Pentium 4.

GCC不会使用默认设置的该指令,而是尝试使用i386中的可用指令来执行此操作:

GCC doesn't uses this instructions set by default and tries to do it with the available instructions from i386:

fldl   0x28(%esp)
fldl   0x403070
fmulp  %st,%st(1)
fnstcw 0x1e(%esp)
mov    0x1e(%esp),%ax
mov    $0xc,%ah
mov    %ax,0x1c(%esp)
fldcw  0x1c(%esp)
fistpl 0x18(%esp)
fldcw  0x1e(%esp)
mov    0x18(%esp),%eax
mov    %eax,0x4(%esp)
movl   $0x403068,(%esp)
call   0x401b44 <printf>
mov    $0x0,%eax

如果您希望GCC使用 cvttsd2si ,需要通过标记 -msse2 来告诉它使用SSE2中可用的期货,但这也意味着有些人仍然使用较旧的计算机将无法运行该程序。请参阅英特尔386和AMD x86-64选项更多选项。

if you want GCC to use cvttsd2si you need to tell it to use the futures available from SSE2 by compiling with the flag -msse2, but also this means that some people who still using older computers won't be able to run this program. See here Intel 386 and AMD x86-64 Options for more options.

因此,在使用 -msse2 进行编译后,它将使用 cvttsd2si 将结果转换为32位整数:

So after compiling with -msse2 it will use cvttsd2si to convert the result to 32 bit integer:

0x004013ac <+32>:    movsd  0x18(%esp),%xmm1
0x004013b2 <+38>:    movsd  0x403070,%xmm0
0x004013ba <+46>:    mulsd  %xmm1,%xmm0
0x004013be <+50>:    cvttsd2si %xmm0,%eax
0x004013c2 <+54>:    mov    %eax,0x4(%esp)
0x004013c6 <+58>:    movl   $0x403068,(%esp)
0x004013cd <+65>:    call   0x401b30 <printf>
0x004013d2 <+70>:    mov    $0x0,%eax

现在MSVC和GCC应提供相同的数字:

now both MSVC and GCC should give the same number:

> type test.c
#include <stdio.h>

int main(int argc, char *argv[])
{

    double f = 18.40;
    printf("%d\n", (int) (10.0  * f));

    return 0;
}
> gcc -Wall test.c -o gcctest.exe -msse2
> cl test.c /W3 /link /out:msvctest.exe
> gcctest.exe
184
> msvctest.exe
184
>