我对汇编语言非常陌生,请多多包涵...
我有一个浮点数,我已经舍入到最接近的.001,但仍显示为+ 1.6670000E + 000。我希望它简单地显示为1.667。
这是我的数字除法和四舍五入代码:
fild num_a
fidiv num_b
fimul thousand
frndint
fidiv thousand
fst a_div_b
这是我用于显示浮点数的代码:
mov eax, num_a
call WriteDec
mov edx, OFFSET divide
call WriteString
mov eax, num_b
call WriteDec
mov edx, OFFSET equals
call WriteString
fld a_div_b
call WriteFloat
call CrLf
我在线上看了很多,关于如何取整数字有很多答案,但是它们仍然全部以扩展格式显示。我正在使用irvine32库。
对注释中讨论的方法进行了更简单的修改:
乘以1000并转换用fistp
进行整数(默认四舍五入到最接近的值),而不是仅使用long double
进行四舍五入为整数值frndint
。
该整数的低3个小数位是数字的小数部分。即,您现在有了十进制定点。 div
乘以1000得到的商(整数部分)和余数(小数部分)。 打印两个部分,它们之间带有.
。]
您将要进行手动int->字符串转换(How do I print an integer in Assembly Level Programming without printf from the c library?)或以其他方式在小数部分打印前导零。 (因此2.062
不会变成2.62
)
这比在FP中分成整数和小数部分要容易得多,在FP中,整数和小数部分需要四舍五入为零,以确保得到非负小数部分。整数除法自然会截断为零,但是传统的x87 FP-> int转换只能使用默认的舍入模式。 (除了SSE3 fisttp
。)自引入以来,SSE1 / 2具有XMM FP-> int转换,具有截断或当前舍入模式,例如cvttsd2si
vs. cvtsd2si
缺点:对于较小的浮点输入,将溢出32位整数
,因为单个32位整数必须保存x * 1000
。另一种方法是使用x - (int)x
获得小数部分,而只将that
1000.0
。这导致(int)x
与小数部分形成一个单独的整数,其中x*1000
仅作为浮点存在,而不存在int32_t
。有趣的事实:
AVX512DQ具有直接获取小数部分的指令:VREDUCESD xmm1, xmm2, xmm3/m64, imm8(和ss / ps / pd版本)。这是SSE4 roundsd / vrndscalesd保留整数部分时将丢弃的部分。更加有趣:可以保留指定数量的分数位。但是,这些当然是二进制小数位,而不是小数位。
如今,大多数x86 CPU具有SSE4.1,但只有Skylake-X高端台式机和现代Xeon具有AVX512DQ。 :/和Ice Lake笔记本电脑。