我对汇编语言很陌生,所以请耐心听我说…
我有一个四舍五入到最近的.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库。
发布于 2020-04-04 07:16:28
对注释中讨论的方法进行了更简单的修改:
乘以1000并使用fistp将其转换为整数(默认舍入为最接近),而不是使用frndint仅舍入为整数值long double。
这个整数的低3位小数是你的数字的小数部分。,即你现在有了小数定点。div乘以1000得到商(整数部分)和余数(小数部分)。打印两部分,中间有一个 . 。
您需要手动执行int->string转换(How do I print an integer in Assembly Level Programming without printf from the c library?),或者在小数部分打印前导零。(这样2.062就不会变成2.62)
这比在FP中分成整数和小数部分更容易,后者需要舍入并截断到零,以确保得到非负的小数部分。整数除法自然会向零截断,但传统的x87 FP->int转换只能使用默认的舍入模式。( SSE3 fisttp除外。)自引入以来,SSE1/2具有带有截断或当前舍入模式的XMM FP->int转换,就像cvttsd2si与cvtsd2si一样
的缺点:对于较小的浮点输入,溢出32位整数,因为单个32位整数必须保存x * 1000。
另一种方法是使用x - (int)x获得小数部分,并仅将该小数部分乘以1000.0。这导致(int)x与小数部分分开,x*1000只作为浮点存在,而不是int32_t。
有趣的事实:
AVX512DQ有一个直接获取小数部分的指令:VREDUCESD xmm1, xmm2, xmm3/m64, imm8 (和ss/ps/pd版本)。这是SSE4 roundsd / vrndscalesd在保留整数部分时会丢弃的部分。更有趣的是:可以保留指定数量的分数位。当然,这些是二进制分数位,而不是十进制位。
如今,大多数Skylake CPU都有AVX512DQ 4.1,但只有Skylake-X高端台式机和现代至强CPU有SSE4.1。:/和冰湖笔记本电脑。
https://stackoverflow.com/questions/61020815
复制相似问题