Допустим, у нас есть две точки (x1, y1)
и (x2, y2)
, тогда расстояние между ними будет вычисляться по формуле
d = sqrt( (y2-y1)2 + (x2-x1)2)
Для нахождения расстояния между точками создадим новый файл distance.s и определим в нем следующий код:
// Функция вычисления расстояния между двумя точками // Входные параметры: // X0 - указатель на 4 числа с плавающей точкой (координаты двух точек x1, y1, x2, y2) // Результат: // X0 - расстояние между точками .global distance distance: STR LR, [SP, #-16]! // сохраняем значение регистра LR в стек LDP S0, S1, [X0], #8 // загружаем координаты первой точки в регистры S0 (x1) и S1 (y1) LDP S2, S3, [X0] // загружаем координаты второй точки в регистры S2 (x2) и S3 (y2) FSUB S4, S2, S0 // S4 = x2 - x1 FSUB S5, S3, S1 // S5 = y2 - y1 FMUL S4, S4, S4 // S4 = S4 * S4 эквивалентно (x2-x1)^2 FMUL S5, S5, S5 // S5 = S5 * S5 эквивалентно (y2-y1)^2 FADD S4, S4, S5 // S4 = S4 + S5 FSQRT S4, S4 // sqrt(S4) - получаем квадратный корень FMOV W0, S4 // помещаем результат в регистр X0 LDR LR, [SP], #16 // восстанавливаем значение регистра LR из стека RET // выходим из функции
Здесь предполагаем, что через регистр X0 в функцию будет передаваться адрес первой координаты. При этом координаты будут представлять четырехбайтные числа с плавающей точкой в виде x1, y1, x2, y2
Сначала загружаем x- и y-координаты первой точки в регистры S0 и S1 соответственно:
LDP S0, S1, [X0], #8
Увеличение адреса в X0 на 8 байт позволяет перейти к следующей паре 4-х байтных координат, которые загружаются в регистры S2 и S3
LDP S2, S3, [X0]
Затем идут стандартные арифметические вычисления в соответствии с формулой нахождения расстояния между точками.
Далее определим файл main.s, который будет использовать эту функцию и также для упрощения будет использовать функцию printf
языка С для вывода полученных значений на консоль:
.global main main: STR LR, [SP, #-16]! LDR X0, =points // загружаем указатель на точки BL distance // вызываем функцию distance // для функции printf языка С надо преобразовать single в double FMOV S2, W0 // перемещаем данные обратно в fpu для преобразования FCVT D0, S2 // преобразуем single в double FMOV X1, D0 // помещаем число double в X1 для форматированного вывода в printf LDR X0, =prtstr // загружаем строку форматирования BL printf // вызываем функцию printf - выводим на консоль полученное расстояние MOV X0, #0 // код возврата LDR LR, [SP], #16 RET .data points: .single 0.0, 0.0, 5.0, 6.0 // две точки в формате x1, y1, x2, y2 для вычисления расстояния prtstr: .asciz "distance = %f\n" // строка форматирования
В данном случае точки представлены четырьямя значениями типа single
points: .single 0.0, 0.0, 5.0, 6.0
То есть у нас две точки (0.0, 0.0) и (5.0, 6.0).
В программе загружаем адрес метки points в регистр X0 и вызываем функцию distance для вычисления расстояния.
Стоит отметить, что функция printf языка С принимает только 64-разрядные числа с плавающей точкой, соответственно нам надо преобразовать single в double. Для этого помещаем результат в регистр S2, с помощью инструкции FCVT преобразуем в double и преобразованный результат передаем в регистр X1 для вывода на консоль:
FMOV S2, W0 // перемещаем данные обратно в fpu для преобразования FCVT D0, S2 // преобразуем single в double FMOV X1, D0 // помещаем число double в X1 для форматированного вывода в printf
Поскольку файл main.s
использует функционал языка С, то скопилируем приложение с помощью компилятора gcc
:
aarch64-none-linux-gnu-gcc main.s distance.s -o main -static
И на консоль будет выведено расстояние между точками:
distance = 7.810250
Аналогично подсчитаем расстояния для несколбких точек:
.global main .equ N, 3 // количество точек main: STP X19, X20, [SP, #-16]! STR LR, [SP, #-16]! LDR X20, =points // загружаем указатель на точки MOV W19, #N // для скольких пар точек надо вычилить расстояние loop: MOV X0, X20 // указатель на первую точку помещаем в X0 BL distance // вызываем функцию distance FMOV S2, W0 // перемещаем даннае обратно в fpu для преобразования FCVT D0, S2 // преобразуем single в double FMOV X1, D0 // помещаем число double в X1 для форматированного вывода в printf LDR X0, =prtstr // загружаем строку форматирования BL printf // вызываем функцию printf - выводим на консоль полученное расстояние ADD X20, X20, #(4*4) // переходим к следующей паре точке для вычисления расстояния - 4 координаты по 4 байта SUBS W19, W19, #1 // уменьшаем счетчик точек B.NE loop // если еще есть точки MOV X0, #0 // код возврата LDR LR, [SP], #16 LDP X19, X20, [SP], #16 RET .data // набор точек points: .single 0.0, 0.0, 5.0, 6.0 .single 1.5, 5.6, 3.2, -1.8 .single 1.234e10, -2.3e-3, 56.35, 6789.123 prtstr: .asciz "distance = %f\n" // строка форматирования
Здесь определяем три пары точек и в цикле для каждой пары вычисляем расстояние. Консольный вывод программы:
distance = 7.810250 distance = 7.592759 distance = 12339999744.000000