Arduino использует программную библиотеку для работы с float (числами с плавающей точкой), которая занимает ~4 КБ Flash и выполняется медленно. Мы напишем свои функции на ассемблере для критических вычислений.
Умножение двух 16-битных чисел (быстрый алгоритм):
.global mul16
; Умножение двух 16-битных чисел
; Вход: R16:R17 = A, R18:R19 = B
; Выход: R24:R25:R26:R27 = A * B (32 бита)
mul16:
PUSH R0
PUSH R1
PUSH R2
PUSH R3
; Копируем операнды
MOV R0, R16
MOV R1, R17
MOV R2, R18
MOV R3, R19
; Обнуляем результат
CLR R24
CLR R25
CLR R26
CLR R27
; Цикл по 16 битам
LDI R20, 16
mul_loop:
; Проверяем младший бит R0
SBRC R0, 0
; Если бит установлен, добавляем B к результату
ADD R24, R2
ADC R25, R3
ADC R26, R1
ADC R27, R1
; Сдвигаем A вправо
LSR R1
ROR R0
; Сдвигаем B влево
LSL R2
ROL R3
DEC R20
BRNE mul_loop
POP R3
POP R2
POP R1
POP R0
RET
Использование в C++:
extern "C" {
uint32_t mul16(uint16_t a, uint16_t b);
}
void setup() {
Serial.begin(115200);
uint32_t result = mul16(12345, 6789);
Serial.print("12345 * 6789 = ");
Serial.println(result);
}
void loop() {}
Быстрый квадратный корень (метод Ньютона на 16 бит):
.global isqrt16
; Целочисленный квадратный корень 16-битного числа
; Вход: R16:R17 = число
; Выход: R24 = корень (8 бит)
isqrt16:
CLR R24
LDI R25, 128 ; Начальное приближение = 128
LDI R20, 8 ; 8 итераций
sqrt_loop:
MOV R22, R24
ADD R22, R25 ; mid = (low + high) / 2
ROR R22
; Вычисляем mid * mid (используем mul16)
MOV R16, R22
MOV R17, R1 ; Обнуляем старший байт
CLR R18
MOV R19, R22
CALL mul16
; Сравниваем mid^2 с входным числом
; ...
DEC R20
BRNE sqrt_loop
RET