これはアセンブリ言語の問題です。ユーザー入力を文字列として受け入れ、それを整数に変換する方法をすでに理解しました
現在の合計に10を掛け(3ずつシフトし、左に1位置シフトしてから、2つの結果を足し合わせます)、文字列から新しい数字を追加します(48を引くことですでに数値に変換されています)
オーバーフローが発生するまではこれで問題ありませんが、2つのレジスタに収まるように数値を分割するにはどうすればよいでしょうか。分割またはビットシフトする必要がありますか?詳しく説明してください!
このためには、倍幅の演算、つまりシフトと加算を合成する必要があります。
シフトでは、両方の半分を別々にシフトする以外に、こぼれたトップビットを下半分から上半分に取り込む必要があります。そのためには、必要に応じて下半分を右にシフトし、ビット単位OR
または加算を使用して上半分に入れます。
擬似コード(論理シフトを使用):
result_low = (orig_low << n)
result_high = (orig_high << n) | (orig low >> (32 - n))
さらに、下半分を処理してから、元のオペランドの1つよりも小さいかどうかを確認します。そうである場合、それはオーバーフローが発生したことを意味し、加数の上位半分と上位半分にキャリーを追加する必要があります。
result_low = op1_low + op2_low
result_high = op1_high + op2_high + ((result_low < op1_low) ? 1 : 0)
可能なasm実装:
la $t2, buff ; pointer to string
li $t0, 0 ; low
li $t1, 0 ; high
loop:
lb $t3, ($t2) ; load next byte
beq $t3, $zero, done ; end of string?
addi $t3, $t3, -48 ; convert from ascii
; t4,5 = t0,1 << 1
srl $t6, $t0, 31 ; t6 is used for the spilled bit
sll $t4, $t0, 1 ; shift low half
sll $t5, $t1, 1 ; shift high half
or $t5, $t5, $t6 ; put in the spilled bit
; t0,1 <<= 3
srl $t6, $t0, 29 ; the 3 spilled bits
sll $t0, $t0, 3 ; shift low half
sll $t1, $t1, 3 ; shift high half
or $t1, $t1, $t6 ; put in the spilled bits
; t0,1 += t4,5
addu $t0, $t0, $t4 ; add low halves
addu $t1, $t1, $t5 ; add high halves
sltu $t6, $t0, $t4 ; t6 = (t0 < t4), that is the carry
addu $t1, $t1, $t6 ; add the carry if any
; ok t0,1 has been multiplied by 10
addu $t0, $t0, $t3 ; just add the digit now
sltu $t6, $t0, $t3 ; the carry
addu $t1, $t1, $t6 ; add the carry if any
addiu $t2, $t2, 1 ; increment pointer
b loop ; and continue
done:
もちろん、シフトの代わりに乗算を直接使用することもできます。
番号はビットシフトされます。wikiに記載されている乗算シーケンスを参照して、LOレジスタとHIレジスタがどのように入力されるかを知ることができます。
LO = (($s * $t) << 32) >> 32;
HI = ($s * $t) >> 32;