如何使用Irvine32 WriteFloat而不是printf显示四舍五入为.001的浮点数

问题描述 投票:0回答:1

我对汇编语言非常陌生,请多多包涵...

我有一个浮点数,我已经舍入到最接近的.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库。

assembly masm irvine32
1个回答
1
投票

对注释中讨论的方法进行了更简单的修改:

乘以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笔记本电脑。

© www.soinside.com 2019 - 2024. All rights reserved.