【问题标题】:Assembly Language Advance Calculator汇编语言高级计算器
【发布时间】:2020-12-03 03:46:15
【问题描述】:

我能从 YouTube 视频中学到的是个位数的乘法或除法。

但是,如果我想计算多个带小数点的数字怎么办?

例如

输入1:123

输入2:320

计算 = 输入 1 x 输入 1 / 输入 2

答案为 47.28(实际答案为 47.278125,但转换为 2 个小数点)

谁能提供例子就好了。谢谢!

【问题讨论】:

    标签: assembly x86 64-bit x86-64


    【解决方案1】:

    使用浮点单元 (FPU)。
    这是您计算的精髓:

    num1    dd 123
    num2    dd 320
    hundred dd 100
    result  dd 0
    ...
    fild  dword [num1]    ; [st0] 123
    fmul  st0             ; [st0] 123 x 123 == 15129
    fidiv dword [num2]    ; [st0] (123 x 123) / 320 == 47.278125
    fimul dword [hundred] ; [st0] ((123 x 123) / 320) * 100 == 4727.8125
    fistp dword [result]  ; floating point stack is empty
    
    

    fimul dword [hundred] 指令的存在是为了在值被存储回主存储器时不会丢失 2 位小数。 fistp dword [result] 指令会将值四舍五入为最接近的整数。

    结果现在包含 4728,您可以将其除以 100 以获得整数部分和 2 位小数:

    mov eax, [result]
    xor edx, edx
    div dword [hundred]   ; -> Quotient EAX == 47, Remainder EDX == 28
    

    根据需要进一步处理这些。

    【讨论】:

    • 由于这是 64 位代码,执行 FP 数学的标准方法是使用 SSE2。从 int 到 FP 的显式转换需要更多指令。 (或者将您的输入提供为双精度,或者至少提供一个100.0 常量)。 SSE 没有像fidiv 这样转换除以转换结果的指令;这是 x87 独有的。但是您可以直接从 double 转换为 EAX,而不需要 result 的内存空间。
    【解决方案2】:

    处理小数值的一种方法是使用fixed-point 表示,这在各种情况下都很有用。例如,神经网络可以利用定点表示和权重量化到improve prediction speed 并减少存储需求。

    在定点中,数字由整数和比例因子表示。例如,2.020 可以用整数2020 和比例因子1/1000 表示。使用为 2 的幂的缩放因子在计算上很方便,因为位移可用于重新缩放。对于某些操作,例如加法和减法,生成的比例因子与操作数的比例因子相匹配。对于乘法,缩放因子相乘,可以使用随后的除法(或位移)重新缩放。对于除法,缩放因子会被除掉,这可以通过对其中一个操作数进行缩放来解释。

    例如,这是问题中示例的x86-64 程序集中的实现,这导致rax 中的47rbx 中的28。我相信按原样使用的除法(和右位移)会引入偏差,因为会有截断而不是舍入。下面的代码一般不处理这个问题,但是对于将小数四舍五入到两位数的情况(否则小数会截断为27)。在右位移之前添加1/2 将在重新缩放时result in rounding。将(divisor - 1) / 2 添加到股息将result in rounding 进行除法。但是,相对于其他错误源,截断 may be small 会产生错误。

      mov rax, 123   ; rax = 123
      imul rax, rax  ; rax *= rax
      shl rax, 8     ; use scaling factor of 2 ^ -8 for the numerator
      mov rbx, 320   ; rbx = 320
      xor rdx, rdx   ; set numerator high bits to 0 for division
      div rbx        ; rax /= rbx
      movzx ebx, al  ; move fractional part from al to bl
      shr rax, 8     ; rescale to unit scaling factor
      imul rbx, 100  ; multiply leftmost two decimals out of fractional part
      add rbx, 0x80  ; if fractional part > 1/2, carry into integer
      shr rbx, 8     ; drop fraction from rbx
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 2013-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-16
      • 1970-01-01
      相关资源
      最近更新 更多