Вычисление расстояния между точками.

Последнее обновление: 20.01.2023

Допустим, у нас есть две точки (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
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850