我使用以下x86汇编指令将摄氏度转换为华氏度:
imul dword [NINE]
idiv dword [FIVE]
add eax, 32
对于相当多的输入,这会产生一个off-by-one错误:
现在,我通过检查有符号的除法除以5的余数,然后相应地舍入来解决这个问题:
imul dword [NINE]
idiv dword [FIVE] ; -> Remainder EDX=[-4,4]
add eax, 32+1
cmp edx, 2
jg @f
dec eax
cmp edx, -2
jge @f
dec eax
@@:
我更喜欢无分支的解决方案,因为我听说它通常会更快。
另外,我怎样才能改变代码,使它返回一个小数?
1条答案
按热度按时间guz6ccqo1#
从摄氏度到华氏度
在x86汇编中,将摄氏温度转换为华氏温度的直接实现使用以下公式:
需要有符号运算,因为摄氏温度和华氏温度也存在于负数范围内。它们的刻度从absolute zero(0 K)开始:Celsius的起始温度为-273.15 °C,Fahrenheit的起始温度为-459.67 °F。
取整
上述代码的一个重要缺点是结果不能正确地舍入到最近的整数。(
idiv
向零舍入,也称为截断。)实现这种舍入的最简单方法是在被除数除以5之前将 * 加 * 2。可悲的是,这只适用于积极的投入。对于负输入,我们宁愿在除以5之前减去 * 2。因此,下一个解决方案通过首先向输入添加合适的偏置来避免 * 有符号 * 除法。代码的其余部分不再需要考虑负数。275的偏差将使任何法律的输入为正,并且不会引入进一步的舍入问题,因为最终将消除偏差的值是整数:(275 * 9 / 5)= 495。
优化
可以用一条
LEA
指令来代替9的乘法运算,该指令可以同时执行几次加法运算。同样可以用乘以5的multiplicative inverse来代替除以5。
精度
使用十进制fixed-point numbers,缩放比例为1/100,我们可以提供精确到小数点后两位的结果。例如,-273.15 °C被存储为带符号整数-27315,并将输出表示-459.67 °F的带符号整数-45967。
从华氏度到摄氏度
在x86汇编中,将华氏温度转换为摄氏温度的直接实现使用以下公式:
需要有符号运算,因为摄氏温度和华氏温度也存在于负数范围内。它们的刻度从absolute zero(0 K)开始:Celsius的起始温度为-273.15 °C,Fahrenheit的起始温度为-459.67 °F。
取整
上述代码的一个重要缺点是结果不能正确地舍入到最近的整数。实现这种四舍五入的最简单方法是在除以9之前将被除数 * 加 * 4。可悲的是,这只适用于积极的投入。对于负输入,我们宁愿在除以9之前减去 * 4。
因此,下一个解决方案通过首先向输入添加合适的偏置来避免 * 有符号 * 除法。代码的其余部分不再需要考虑负数。偏置495将使任何法律的输入为正,并且不会引入进一步的舍入问题,因为最终将消除偏置的值是整数:(495 * 5 / 9)= 275。
优化
可以用一条
LEA
指令来代替5的乘法运算,该指令同时可以进行几次加法运算。同样可以用乘以9的multiplicative inverse来代替除以9。
精度
使用十进制fixed-point numbers,缩放比例为1/100,我们可以提供精确到小数点后两位的结果。例如-459.67 °F被存储为带符号整数-45967,并将输出表示-273.15 °C的带符号整数-27315。
| 四|-15!|-16|-16| -15.56 | -15.555555 |
| 五|-15|-15|-15| -15.00 |-15|
| 六|-14|-14|-14| -14.44 | -14.444444 |
| 七|-13!|-14|-14| -13.89 | -13.888888 |
| 八|-13|-13|-13| -13.33 | -13.333333 |
| 九|-12!|-13|-13| -12.78 | -12.777777 |
| 10个|-12|-12|-12| -12.22 | -12.222222 |