ftol2 の関数を調べてみて分かった事

ftol は float(浮動小数点) から long 型、
ftol2 は float(浮動小数点) から long^2 型つまりlonglong型64bit 整数に変換する関数だと長いこと思っていました。

ところが、VC++ のインライン関数を調べてみるとそうでないことが分かりました

_ftol2_sse:
00411640 83 3D B8 75 41 00 00 cmp         dword ptr [___sse2_available (4175B8h)],0
00411647 74 2D            je          _ftol2 (411676h)
_ftol2_pentium4:
00411649 55               push        ebp  
0041164A 8B EC            mov         ebp,esp
0041164C 83 EC 08         sub         esp,8
0041164F 83 E4 F8         and         esp,0FFFFFFF8h
00411652 DD 1C 24         fstp        qword ptr [esp]
00411655 F2 0F 2C 04 24   cvttsd2si   eax,mmword ptr [esp]
0041165A C9               leave            
0041165B C3               ret              

_ftol2_sse_excpt:
0041165C 83 3D B8 75 41 00 00 cmp         dword ptr [___sse2_available (4175B8h)],0
00411663 74 11            je          _ftol2 (411676h)
00411665 83 EC 04         sub         esp,4
00411668 D9 3C 24         fnstcw      word ptr [esp]
0041166B 58               pop         eax  
0041166C 66 83 E0 7F      and         ax,7Fh
00411670 66 83 F8 7F      cmp         ax,7Fh
00411674 74 D3            je          _ftol2_pentium4 (411649h)
_ftol2:
00411676 55               push        ebp  
00411677 8B EC            mov         ebp,esp
00411679 83 EC 20         sub         esp,20h
0041167C 83 E4 F0         and         esp,0FFFFFFF0h
0041167F D9 C0            fld         st(0)
00411681 D9 54 24 18      fst         dword ptr [esp+18h]
00411685 DF 7C 24 10      fistp       qword ptr [esp+10h]
00411689 DF 6C 24 10      fild        qword ptr [esp+10h]
0041168D 8B 54 24 18      mov         edx,dword ptr [esp+18h]
00411691 8B 44 24 10      mov         eax,dword ptr [esp+10h]

00411695 85 C0            test        eax,eax
00411697 74 3C            je          integer_QnaN_or_zero (4116D5h)
arg_is_not_integer_QnaN:
00411699 DE E9            fsubp       st(1),st
0041169B 85 D2            test        edx,edx
0041169D 79 1E            jns         positive (4116BDh)
0041169F D9 1C 24         fstp        dword ptr [esp]
004116A2 8B 0C 24         mov         ecx,dword ptr [esp]
004116A5 81 F1 00 00 00 80 xor         ecx,80000000h
004116AB 81 C1 FF FF FF 7F add         ecx,7FFFFFFFh
004116B1 83 D0 00         adc         eax,0
004116B4 8B 54 24 14      mov         edx,dword ptr [esp+14h]
004116B8 83 D2 00         adc         edx,0
004116BB EB 2C            jmp         localexit (4116E9h)
positive:
004116BD D9 1C 24         fstp        dword ptr [esp]
004116C0 8B 0C 24         mov         ecx,dword ptr [esp]
004116C3 81 C1 FF FF FF 7F add         ecx,7FFFFFFFh
004116C9 83 D8 00         sbb         eax,0
004116CC 8B 54 24 14      mov         edx,dword ptr [esp+14h]
004116D0 83 DA 00         sbb         edx,0
004116D3 EB 14            jmp         localexit (4116E9h)
integer_QnaN_or_zero:
004116D5 8B 54 24 14      mov         edx,dword ptr [esp+14h]
004116D9 F7 C2 FF FF FF 7F test        edx,7FFFFFFFh
004116DF 75 B8            jne         arg_is_not_integer_QnaN (411699h)
004116E1 D9 5C 24 18      fstp        dword ptr [esp+18h]
004116E5 D9 5C 24 18      fstp        dword ptr [esp+18h]
localexit:
004116E9 C9               leave            
004116EA C3        &
nbsp;      ret              

赤文字のところに注目、これ、どう見ても、double から 32bit long 型への変換

ftol2_sse やftol2_pentium4 は、 ftol2 の名前を関してるにもかかわらず、変換先が longlong ではなかったという
|。・ω・) 。o (えー!なんで?)

一方の、 ftol2 の素の処理をみると、ちゃんと 64bit long long で処理を行っている。

試行錯誤してみたら、
int ii=(double)xx;
のような処理は ftol2_sse がコールされるけど、
long long ii=(double)xx;
のような処理は ftol2 がコールされることが分かったよ・ω・

だるだる団 DaruDaruDan プログラムメモ - (PC,Android,OpenGL)

Visual C++ 2002 以降では float/double から__int64/int の変換に_ftol2 を使い、
2005 以降では更に float/double から int の変換に _ftol2_sse を試行した後
_ftol2 を使用する。
これらの関数の中では浮動小数点制御ワードの変更を行わず切り捨てを実現する。
_ftol2 の中では浮動小数点のビット表現を利用した計算のみで切り捨てを行う。

確かにこの通りになった。

c++ - _ftol2_sse, are there faster options? - Stack Overflow

global _startsection
.dataalign 16

section
.text_start:
   cvtps2dq  xmm1, [fv1]
; Convert four 32-bit(single precision)
;floats to 32-bit(double word) integers
;and place the result in xmm1

速くなるかな?と思ったら 4つの浮動小数点を32bitの4つの結果に格納なので違った・ω・

c++ - Incorrect double to long conversion - Stack Overflow
これを見ると、VC++2010以前のftol2にはバグがある(一番上のコード)って書いてる。

    push        ebp
    mov         ebp,esp
    add         esp,0FFFFFFF4h
    wait
    fnstcw      word ptr [ebp-2]
    wait
    mov         ax,word ptr [ebp-2]
    or          ah,0Ch
    mov         word ptr [ebp-4],ax
    fldcw       word ptr [ebp-4]
    fistp       qword ptr [ebp-0Ch]
    fldcw       word ptr [ebp-2]
    mov         eax,dword ptr [ebp-0Ch]
    mov         edx,dword ptr [ebp-8]
    leave
    ret

大人しくこれ使うしかないのかしら・ω・(VC++6のコード)

    LONGLONG ull = 0xf000000000000000;
    printf("%I64X\n",ull);
    double xx=ull;
    printf("%f\n",xx);
    LONGLONG tt=xx;
    printf("%I64X\n",tt);

試してみたら、普通に表示できた・ω・;
なるほどわからん!

おすすめ

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です