Konvertieren einer Zahl in eine Zeichenfolge mithilfe der FPU

Jeder, der gerne programmiert, ist verpflichtet, seine eigene Version der Lösung für dieses Problem zu schreiben. Ich beschloss, keine Ausnahme zu sein.





In Übereinstimmung x64 software conventions



damit gehen wir davon aus, dass sich die zu konvertierende Nummer in befindet XMM0



.





Wir werden x64



Bitcode für die x32



Bitadressierung verwenden. Diese Art der Adressierung ermöglicht es Ihnen, beide Dialekte zu nutzen.





Speichern Sie den Stapelwert und erstellen Sie einen absatzausgerichteten Datenpunkt, um die Leistung zu verbessern:





	;  
	mov    r9d, esp
	lea    r8d,[r9d - 70h]
	and    r8d, 0FFFFFFF0h
	mov    esp, r8d
      
      



Wir bereiten es vor, indem wir FPU



es von Daten befreien und die erhöhte Genauigkeit und Rundung auf Null setzen:





	fsave [esp]
	finit
	mov  dword ptr[esp - dword], 037F0F7Fh
	fldcw         [esp - dword]
      
      



Wir überladen die Nummer von XMM0



bis FPU



:





	movd qword ptr[esp - xmmword], xmm0
	fld  qword ptr[esp - xmmword]
      
      



Finden Sie die Dezimalreihenfolge der Zahl:





	fld     st(0)
	fxtract
	fldl2t
	fst     st(1)
	fdivr   st(0),st(2)
	frndint
      
      



Stellen Sie die Rundung auf die nächste Zahl ein:





	fldcw	[esp - word]
      
      



Wir behalten die Reihenfolge der Zahl bei und finden die Dezimalreihenfolge des Multiplikators, um die signifikanten Ziffern der Zahl in den ganzzahligen Teil umzuwandeln:





	fist      dword ptr[esp - dword]
	movzx edx, word ptr[esp - dword]
	mov       dword ptr[esp - dword], 10h
	fisubr    dword ptr[esp - dword]
      
      



Suchen Sie den Dezimalmultiplikator und multiplizieren Sie ihn mit der Zahl:





	fmulp   st(1),st(0)
	fst     st(1)
	frndint
	fsub    st(1),st(0)
	fld1
	fscale
	fstp    st(1)
	fmulp   st(2),st(0)
	f2xm1
	fld1
	faddp   st(1),st(0)
	fmulp   st(1),st(0)
	frndint
      
      



Wir laden die resultierende Zahl aus FPU



Registern AX



und XMM0



in der Größe der ersten 2 bzw. 8 nachfolgenden Bytes neu. Beim Laden von 8 Bytes in ein Register XMM0



ändern wir gleichzeitig die Reihenfolge der Bytes, indem wir den Stapelzeiger durch den Absatz vorab ausrichten:





	fbstp           tbyte ptr[esp - xmmword]
	mov       ax,    word ptr[esp -   qword]
	pshuflw xmm0, xmmword ptr[esp - xmmword], 00011011b
      
      



Wir stellen den Zustand wieder her FPU



:





	frstor [esp]
      
      



0



:





	punpcklbw xmm0, xmm0
	pshuflw   xmm0, xmm0, 10110001b
	pshufhw   xmm0, xmm0, 10110001b
      
      



:





	mov            dword ptr[esp], 0FF00FF0h
	pshufd xmm1, xmmword ptr[esp], 0
	pand   xmm0, xmm1
	psrlw  xmm1, 4
	movdqa xmm2, xmm1
	pand   xmm1, xmm0
	psrlw  xmm1, 4
	pandn  xmm2, xmm0
	paddb  xmm1, xmm2
      
      



:





	pxor    xmm0, xmm0
	pcmpeqb xmm0, xmm1
      
      



:





	mov            dword ptr[esp], 30303030h
	pshufd xmm2, xmmword ptr[esp], 0
	paddb  xmm1, xmm2
      
      



:





	mov  byte ptr[esp],'-'
	btr             ax, 0Fh
	adc            esp, 0
	add             ax,'.0'
	mov  word ptr[esp], ax
      
      



0



:





	movdqu	      xmmword ptr[esp + word], xmm1
	pmovmskb ecx, xmm0
	bsf      ecx, ecx
	add      esp, ecx
      
      



:





	mov    ecx,(word + dword)
	mov    eax, edx
	neg     dx
	jnc     @f
	cmovns eax, edx
	setns   dh
      
      



:





	cmp   ax, 0Ah
	sbb  ecx, ecx
	mov   dl, 0Ah
	div   dl
	cmp   al, 0Ah
	sbb  ecx, 0
	shl  eax, 8
	shr   ax, 8
	div   dl
	add eax, 303030h
	lea edx,[edx * 2 + 2B51h]
	
	mov dword ptr[esp + word + ecx + word], eax
	mov  word ptr[esp + word], dx
      
      



EAX



ECX



:





@@:	lea ecx,[esp + ecx + qword]
	sub ecx, r8d
  mov eax,ecx
      
      



XMM1



XMM2



:





	movdqa xmm1, xmmword ptr[r8d]
	movdqa xmm2, xmmword ptr[r8d + xmmword]
      
      



:





	mov esp, r9d
      
      



.





/ . x64 software conventions



.






- .





- , .





- .





- SIMD



FPU



.





, - .








All Articles