|
Деление/умножение чисел на ассемблере |
|
|
|
Jun 24 2008, 10:42
|

Частый гость
 
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414

|
Доброго всем времени суток! Пишу программу для atmega8535. Недавно начал изучать asm и встала такая задача: Необходимо написать аналог следующего C-кода на asm: Код uint16_t temp1, temp2, temp3; ........ temp1 = temp2/1024*temp3; , где temp3 может иметь значения от 1 до 1023; Данное вычисление должно выполняться максимально быстро. Слышал, что имеется волшебная команда lsr, что соответствует делению на 2, т.о. выполнив 10 раз lsr мы поделим temp2 на 1024, но результат при этом будет <0, что недопустимо, поскольку используется целые числа  Помогите разобраться!
|
|
|
|
|
 |
Ответов
(1 - 9)
|
Jun 24 2008, 10:48
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(Sprite @ Jun 24 2008, 13:42)  Код uint16_t temp1, temp2, temp3; ........ temp1 = temp2/1024*temp3; ... выполнив 10 раз lsr мы поделим temp2 на 1024, но результат при этом будет <0, что недопустимо, поскольку используется целые числа Достаточно вспомнить, что Ваше выражение эквивалентно следующему temp1 = temp2*temp3/1024; т.е. вначале выполняйте умножение, а затем - деление (если нужно - с округлением результата) P.S. Кстати, при делении на 1024 сдвигать на 10 вовсе не требуется - младший байт делимого можно просто отбросить (экономия = 8 сдвигов).
|
|
|
|
|
Jun 24 2008, 10:58
|

Частый гость
 
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414

|
Цитата(aaarrr @ Jun 24 2008, 17:49)  Сначала умножьте temp2 на temp3, а потом делите сдвигом на 1024. Поправка: temp2 принимает значение от 500 до 1500. Спасибо за совет, еще 2 вопроса: 1. Как выполняется умножение на asm? 2. Как быть, если temp2==1000 и temp3==1000? При этом результат операции умножения == 1000000, что выходит за границы максимального значения типа uint16==65535. Нужно использовать числа бОльшей разрядности?
|
|
|
|
|
Jun 24 2008, 11:08
|
Частый гость
 
Группа: Свой
Сообщений: 186
Регистрация: 23-04-06
Из: Сочи
Пользователь №: 16 411

|
Резульатат не будет меньше нуля, т.к. Uint беззнаковый Uint = 16 разрядов. По правилу сокращения погрешности вычислений  сначала осуществляем умножение temp2*temp3 получаем 4 байта = 32 бита, а затем осуществлем деление на 1024 путем сдвига на 10 разрядов с помощью lsr. В итоге результат получится целым и 22-х битным. Что же касается умножения, то тут лучше воспользоваться ATMEL ApplicationNotes. Там есть примеры умножения/деления на асме. ApplicationNotes мона скачать на сайте атмела, а также они есть в проге AVRStudio в папке AVRASSEMBLER Удачи
|
|
|
|
|
Jun 24 2008, 14:12
|

Частый гость
 
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414

|
Цитата(Палыч @ Jun 24 2008, 18:09)  У Atmel на сайте есть документ "AVR200 Multiply and Divide Routines". Скачайте и прочтите При перемножении двух 16-тиразрядных чисел - результат: 32-разрядное число Большое спасибо! Нашел в Appnotes примеры быстрого умножения. Все работает, после умножения результат сохраняется в r18, r19, r20, r21 (r18 - младший байт). Теперь мне необходимо поделить на 1024. Эта операция соответствует 10-ти сдвигам вправо (команда lsr). Но lsr применяется только к 8-битным регистрам. Я делаю следующее: Код mov r21, r20 mov r20, r19 mov r19, r18 Т.е. сдвигаю результат на 8 бит вправо. Далее мне необходимо сдвинуть весь результат еще на 2 бита вправо, но как это сделать я пока не знаю. При сдвиге командой lsr каждого из регистров (r18, r19, r20) теряются два старших бита каждого из регистров. Подскажите, как выполнить сдвиг сразу трех регистров?
|
|
|
|
|
Jun 24 2008, 14:43
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(Sprite @ Jun 24 2008, 17:12)  Подскажите, как выполнить сдвиг сразу трех регистров? Обычно это делают через бит переноса (С). Если у Вас делится положительное число (знак расширять нет необходимости, он всегда 0), то сдвиг трёх байт на 1 бит: clc ror r21 ror r20 ror r19 При "отбрасывании" младшего байта (сдвиг на 8) нет необходимости три других копировать, достаточно помнить, что теперь младший r19 P.S. Ой! Можно то, короче lsr r21 ror r20 ror r19
|
|
|
|
|
Jun 24 2008, 16:27
|

Частый гость
 
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414

|
Цитата P.S. Ой! Можно то, короче
lsr r21 ror r20 ror r19 Спасибо большущщее! Все получилось!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|