Вариант конвертирования double / real8
в строку посредством с SIMD
использованием FPU
в качестве вспомогательного средства. Применение FPU вызвано желанием получить 16 значащих цифр.
В соответствии с x64 software conventions
будем считать что число подлежащие конвертированию расположено в XMM0
.
Будем использовать x64
битный код при x32
битной адресации. Такой способ адресации позволяет использовать преимущества обоих диалектов.
Будем использовать недокументированное соглашение о передаче / возврате из функции множественных параметров. Соглашение абсолютно зеркально соглашению x64 software conventions
за тем исключением что описывает правила размещения параметров при выходе из процедуры.
ROUND_TOWARD_ZERO equ 11b
SIGNIFICANT_BIT_RESET equ 3Fh
NUMBER_OF_SIGNIFICANT_DIGITS equ 40E00000h
LCW equ word
LIExp2 equ dword
LIExp10 equ dword
LSExp10 equ dword
LIUpPathNam equ dword
LILowPathNam equ dword
LNamber equ qword
LMulExp2 equ qword
LStX equ tbyte
LString equ xmmword * 2
.data
f10m4 real4 4 dup (1.0e-4)
f10p4 real4 4 dup (1.0e+4)
f10m2 real4 4 dup (1.0e-2)
f10p2 real4 4 dup (1.0e+2)
f10m1 real4 4 dup (1.0e-1)
f10p1 real4 4 dup (1.0e+1)
f0001 real4 0.0, 1.0e-2, 1.0e-1, 1.0
f0002 real4 0.0, 0.0, 1.0e+1, 1.0e+1
f10p8 real4 1.0e+8
NoSD real4 7.0
i30h db 10h dup (30h)
CW0 dw 0F7Fh
CW1 dw 037Fh
DotM dw 652Dh
namber real8 -1.234567890123456e+248
.code
WinMain proc
movd xmm0, namber
fstcw word ptr[esp - LCW]
fstp tbyte ptr[esp - LCW - LStX]
fldcw CW0
movd rax, xmm0
mov dword ptr[esp - LString - dword], 2D000000h
btr rax, SIGNIFICANT_BIT_RESET
setnc byte ptr[esp - LString - dword - byte]
mov qword ptr[esp - LCW - LStX - LNamber], rax
shr rax, 34h
sub eax, 3FFh
mov dword ptr[esp - LCW - LStX - LNamber - LIExp2], eax
fldlg2
fimul dword ptr[esp - LCW - LStX - LNamber - LIExp2]
fsubr NoSD
fistp dword ptr[esp - LCW - LStX - LNamber - LIExp10]
fldl2t
fimul dword ptr[esp - LCW - LStX - LNamber - LIExp10]
fist dword ptr[esp - LCW - LStX - LNamber - LIExp10 - LIExp2]
fisub dword ptr[esp - LCW - LStX - LNamber - LIExp10 - LIExp2]
f2xm1
cvtsi2ss xmm0, dword ptr[esp - LCW - LStX - LNamber - LIExp10]
mov eax, dword ptr[esp - LCW - LStX - LNamber - LIExp10 - LIExp2]
add ax, 3FFh
shl rax, 34h
mov qword ptr[esp - LCW - LStX - LNamber - LMulExp2], rax
xor edx, edx
pxor xmm1, xmm1
comiss xmm1, xmm0
jz @f
shufps xmm0, xmm0, 0
subps xmm1, xmm0
maxps xmm0, xmm1
mulps xmm0, xmmword ptr f0001
roundps xmm0, xmm0, ROUND_TOWARD_ZERO
pshufd xmm1, xmm0, 10010000b
mulps xmm1, xmmword ptr f0002
subps xmm0, xmm1
cvtps2dq xmm0, xmm0
pxor xmm1, xmm1
pcmpeqd xmm1, xmm0
packusdw xmm0, xmm0
packuswb xmm0, xmm0
mov eax, 2B65h
cmovc ax, DotM
movmskps ecx, xmm1
bsr ecx, ecx
lea ecx,[ecx * 8 - 8]
movd edx, xmm0
add edx, 30303000h
shrd rdx, rdx, cl
mov dx, ax
@@: fmul qword ptr[esp - LCW - LStX - LNamber - LMulExp2]
fadd qword ptr[esp - LCW - LStX - LNamber - LMulExp2]
fmul qword ptr[esp - LCW - LStX - LNamber]
fist dword ptr[esp - LCW - LStX - LILowPathNam - LIUpPathNam]
fisub dword ptr[esp - LCW - LStX - LILowPathNam - LIUpPathNam]
fmul f10p8
fldcw CW1
fistp dword ptr[esp - LCW - LStX - LIUpPathNam]
fld tbyte ptr[esp - LCW - LStX]
fldcw word ptr[esp - LCW]
movq xmm0, qword ptr[esp - LCW - LStX - LIUpPathNam - LILowPathNam]
cvtdq2ps xmm0, xmm0
movaps xmm1, xmm0
mulps xmm0, xmmword ptr f10m4
roundps xmm0, xmm0, ROUND_TOWARD_ZERO
movaps xmm2, xmm0
mulps xmm2, xmmword ptr f10p4
subps xmm1, xmm2
unpcklps xmm0, xmm1
movaps xmm1, xmm0
mulps xmm0, xmmword ptr f10m2
roundps xmm0, xmm0, ROUND_TOWARD_ZERO
movaps xmm2, xmm0
mulps xmm2, xmmword ptr f10p2
subps xmm1, xmm2
movaps xmm2, xmm1
mulps xmm1, xmmword ptr f10m1
roundps xmm1, xmm1, ROUND_TOWARD_ZERO
movaps xmm3, xmm1
mulps xmm3, xmmword ptr f10p1
subps xmm2, xmm3
cvtps2dq xmm1, xmm1
cvtps2dq xmm2, xmm2
pslld xmm2, 8
paddb xmm1, xmm2
movaps xmm2, xmm0
mulps xmm0, xmmword ptr f10m1
roundps xmm0, xmm0, ROUND_TOWARD_ZERO
movaps xmm3, xmm0
mulps xmm3, xmmword ptr f10p1
subps xmm2, xmm3
cvtps2dq xmm0, xmm0
cvtps2dq xmm2, xmm2
pslld xmm2, 8
paddb xmm0, xmm2
pslld xmm1, 16
paddb xmm0, xmm1
pxor xmm3, xmm3
pcmpeqb xmm3, xmm0
pmovmskb eax, xmm3
bts eax, 10h
bsr eax, eax
paddb xmm0, xmmWord ptr i30h
movdqu [esp - LString + byte], xmm0
mov qword ptr[esp - LString + byte + eax], rdx
movd xmm0, rdx
pxor xmm1, xmm1
pcmpeqb xmm1, xmm0
pmovmskb edx, xmm1
bsf edx, edx
lea eax,[eax + edx + word + byte]
mov dl,[esp - LString + byte]
mov dh,'.'
mov [esp - LString], dx
mov ecx, dword ptr[esp - LString - dword - byte]
sub eax, ecx
movdqu xmm1, xmmword ptr[esp - LString + ecx - byte]
movdqu xmm2, xmmword ptr[esp - LString + ecx - byte + xmmword]
mov ecx, eax
WinMain endp
end
Зачем писать этот код если ранее ты уже разместил код про который заявил что он самый быстрый - потому что этот код еще быстрей.
Чем он лучше предыдущего - в этом коде векторизовано разложение Числа на числа.
Почему в нем одновременно используются FPU
и SIMD
- потому что в FPU
есть режим расширенной точности позволяющий извлечь 16 значащих цифр.