vak: (Default)
Serge Vakulenko ([personal profile] vak) wrote2024-11-09 09:31 pm

Вычисляем кубический корень на ассемблере RISC-V

Ликбез по ассемблеру RISC-V (часть 1, часть 2) был бы неполным без вещественной арифметики. Редкий микроконтроллер имеет плавающую точку, да ещё 64-битную. Получим же от неё удовольствие на PIC64. 😀

Вычислим что-нибудь простое но нетривиальное, скажем кубический корень. Итеративный алгоритм Ньютона вполне годится. Добывая корень из числа n, следующую итерацию x вычисляем как next_x = (n/x/x + x + x) / 3. На ассемблере будет выглядеть так:
        .text
cubic_root:
fmv.d fa3, fa0 # n in register fa3
fld fa2, three, a5 # constant 3.0
fld fa0, one, a5 # x = 1.0, initial guess
loop:
fdiv.d fa5, fa3, fa0 # n / x
fmv.d fa4, fa0 # old x in register fa4
fdiv.d fa5, fa5, fa0 # n / x / x
fadd.d fa5, fa5, fa0 # + x
fadd.d fa5, fa5, fa0 # + x
fdiv.d fa0, fa5, fa2 # divide by 3.0
feq.d a5, fa4, fa0 # nx == x?
beqz a5, loop # otherwise to next iteration
ret

one: .double 1.0
three: .double 3.0
На этот раз мне лениво писать на ассемблере печать вещественного числа. Воспользуемся стандартной функцией printf(). Её вариант __printf_chk можно вызывать прямо из ассемблера.
        .globl  main
main:
fld fs0, input, a5 # input value
fmv.d fa0, fs0 # copy to permanent register
call cubic_root

li a0, 2
lla a1, format
fmv.x.d a2, fs0 # input value
fmv.x.d a3, fa0 # square root
call __printf_chk

li a0, 0 # exit status
call _exit

input: .double 2.0
format: .string "cubic root of %.15g is %.15g\n"
Компилируем, запускаем.
$ cc -o cubic_root cubic_root.s

$ ./cubic_root
cubic root of 2 is 1.25992104989487
Всё оказывается ничуть не сложнее, чем с целочисленными вычислениями.

Post a comment in response:

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org