Как сделать деление в ARM?

Я пытаюсь найти, как сделать деление в ARM, так как нет команды DIV. Если это можно сделать умножением числа с плавающей запятой [/9 = *0.09], вычитанием или использованием библиотеки. Любой способ подойдет.

В настоящее время я делаю деление с помощью вычитания, используя такой цикл, но я теряю десятичные дроби:

MOV R0,#70 ;Fahrenheit Temperature
SUB R1,R0,#32 ; Subtracting 32
MOV R4,#0 ;Counter

LOOP 

   ADD R4,R4,#1; Counter+1 ->Is the answer of the division without decimals
   SUB R1,#9
   CMP R1,#0
   BPL LOOP
   MOV R1,R4

Итак, в основном, что я делаю, так это то, что у меня есть температура 70, я вычитаю 32 и получаю 38. Затем в цикле я беру 9 каждый раз, пока напоминание не станет меньше 9. Ответ с использованием обычного деления: 4,22222. Здесь я получаю 5. Так что мой результат не такой точный.


person Antreas Solou    schedule 07.11.2013    source источник
comment
возможный дубликат Fast Division на GCC/ARM   -  person artless noise    schedule 07.11.2013
comment
Лучше умножить на что-то вроде (2 ^ 16/9 ~ = 7282), а затем сдвинуть результат на 2 ^ 16. Вы должны знать диапазон значений, и это работает только для фиксированного деления.   -  person artless noise    schedule 07.11.2013
comment
Другие связанные вопросы: Целочисленное деление на ARM, Алгоритм сборки мода; посмотрите на соответствующий список рядом с вопросом.   -  person artless noise    schedule 07.11.2013
comment
В моем ARM есть инструкция деления, а в вашем нет? Не могли бы вы дать нам немного больше информации?   -  person    schedule 07.11.2013
comment
homepage.cs.uiowa.edu/~jones/bcd/divide.html и просто сделайте это для любого другого числа. да, вы можете использовать фиксированное или плавающее значение, например, для умножения на 1/9.   -  person old_timer    schedule 08.11.2013


Ответы (2)


Если вы просто хотите разделить целочисленное значение в r0 на 9, вы можете аппроксимировать это с помощью:

ldr r3,=0x1C71C71D   # 1C71C71D == (2^32 / 9) + 1
umull   r9,r3,r0,r3

r3 теперь содержит целую часть частного, а r9 содержит дробную часть, масштабированную на 2^32. Чтобы получить остаток, нужно просто умножить целую часть частного на 9 и вычесть результат из исходного значения.

person Michael    schedule 07.11.2013
comment
Это деление на умножение. Подробнее читайте здесь - person phuclv; 08.11.2013
comment
@AntreasSolou: umull умножает два 32-битных числа, чтобы сформировать 64-битный результат (разделенный на два регистра). Таким образом, код формирует 32.32 число с фиксированной точкой в r3 (целая часть ) и r9 (дробная часть), что равно (r0 << 32) / 9. - person Michael; 08.11.2013
comment
Точное деление, которое работает для всех входов uint32_t, см. в выводе GCC8.2: godbolt.org/z/-PVI_Q использует другой множитель, который требует сдвига вправо на 1 после umull, но это все. - person Peter Cordes; 10.04.2019

Ответ Майкла правильный, если вы делите число на константу и вам нужен целочисленный результат. Вы не получите дробную часть, как хотите.

Если вам нужен результат с плавающей запятой, вам понадобится функция деления с плавающей запятой, которую нелегко реализовать в программном обеспечении и ассемблере на архитектурах без FPU. ARMv7 и выше имеют FPU/SIMD по умолчанию, некоторые ARMv6 и ниже также имеют FPU, поэтому вы можете разделить его непосредственно на оборудовании.

Решение с фиксированной точкой может быть проще, просто разделите число, как обычное целочисленное деление, но не забудьте скорректировать результат после вычисления. Конечно, число с фиксированной запятой не будет иметь большого динамического диапазона, такого как число с плавающей запятой, но в вашем случае я думаю, что диапазона достаточно. Вы также можете умножить остаток на 10n, где n – это необходимое количество цифр после запятой, а затем снова разделить его на указанный выше делитель, чтобы получить дробную часть.

Например, чтобы получить результат 22/9 с точностью до 3 цифр, выполните следующие действия:

22/9   = 2 remains 4
4*10^3 = 4000
4000/9 = 444
→ 22/9 = 2.444

Чтобы получить большую точность, просто умножьте остаток на большую степень 10.

person phuclv    schedule 08.11.2013
comment
Более сложный трюк с умножением (Почему GCC использует умножение на странное число при реализации целочисленного деления?) на самом деле является обратным мультипликативным методом с фиксированной точкой, так что вы можете использовать это, чтобы получить несколько дробных битов. Обычно вы сохраняете только целую часть из старшей половины полного результата. Ответ Майкла выглядит проще, чем то, что gcc использует для точного деления: godbolt.org/z/0YfBFt предполагает смену после umull. - person Peter Cordes; 10.04.2019