Целочисленное деление на константу
-
orinoko
Целочисленное деление на константу
Подскажите пожалуйста реализацию целочисленного деления 3-байтного беззнакового числа на константу (а конкретно - на 200). АТмега128, ассемблер, 16 МГц. Ограничение по времени выполнения - не более 80 мкс. Хочу оптимизировать часть программы - но вот что-то у меня такая задача в тупик поставила.
- Реклама
- ibiza11
- Поставщик валерьянки для Кота
- Сообщения: 1900
- Зарегистрирован: Сб фев 21, 2009 13:11:40
- Откуда: Москва
Re: Целочисленное деление на константу
здесь посмотрите http://www.atmel.com/Images/doc0936.pdf
и здесь http://www.mikrocontroller.net/articles/AVR_Arithmetik
и здесь http://www.mikrocontroller.net/articles/AVR_Arithmetik
Ставим плюсы: )
-
orinoko
Re: Целочисленное деление на константу
Спасибо. Надо будет внимательно поизучать.
Re: Целочисленное деление на константу
откомпилировал в WinAVR простую строчку b = a / 200; для 32-разрядных беззнаковых переменных. в симуляторе выполняется за 600 с небольшим тактов (пробовал с разными значениями вплоть до 0xFFFFFF). итого, для 16 МГц - не более 40 мкс.
вот ассемблерный листинг (убрал немного лишнего, можно еще сократить), может, поможет:
вот ассемблерный листинг (убрал немного лишнего, можно еще сократить), может, поможет:
Спойлер
Код: Выделить всё
; вход:
; r22 - r25 - делимое
; r18 - r21 - делитель (=200)
...
call udivmodsi4
...
; выход:
; r22 - r25 - частное
udivmodsi4:
ldi r26, 0x21 ; 33
mov r1, r26
sub r26, r26
sub r27, r27
movw r30, r26
rjmp udivmodsi4_ep
udivmodsi4_loop:
adc r26, r26
adc r27, r27
adc r30, r30
adc r31, r31
cp r26, r18
cpc r27, r19
cpc r30, r20
cpc r31, r21
brcs udivmodsi4_ep
sub r26, r18
sbc r27, r19
sbc r30, r20
sbc r31, r21
udivmodsi4_ep:
adc r22, r22
adc r23, r23
adc r24, r24
adc r25, r25
dec r1
brne udivmodsi4_loop
com r22
com r23
com r24
com r25
ret-
orinoko
Re: Целочисленное деление на константу
спасибо за то, что отклюкнулись, сохраню на всякий случай, но я только что закончил делать для 24-разрядных. получилось, и даже делит правильно
, по времени 28 мкс.
- Реклама
- ChipKiller
- Сверлит текстолит когтями
- Сообщения: 1163
- Зарегистрирован: Ср янв 05, 2011 16:25:15
Re: Целочисленное деление на константу
... можно вспомнить, что X/((0x10000/200)/0x10000)=(X*~328)>>16 ... возможно получится быстрееполучилось, и даже делит правильно, по времени 28 мкс.
- Gudd-Head
- Друг Кота
- Сообщения: 20092
- Зарегистрирован: Чт сен 18, 2008 12:27:21
- Откуда: Столица Мира Санкт-Петербург
Re: Целочисленное деление на константу
Поделить пополам сдвигом вправо, перевести в BCD и отбросить 2 младшие цифры 
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
- ChipKiller
- Сверлит текстолит когтями
- Сообщения: 1163
- Зарегистрирован: Ср янв 05, 2011 16:25:15
Re: Целочисленное деление на константу
.. так уж точно будет не быстрееGudd-Head писал(а):Поделить пополам сдвигом вправо, перевести в BCD
PS. если нужно точнее можно так X/200=(X*83886)>>24 ... 24 сдвига конечно делать не надо
- Gudd-Head
- Друг Кота
- Сообщения: 20092
- Зарегистрирован: Чт сен 18, 2008 12:27:21
- Откуда: Столица Мира Санкт-Петербург
Re: Целочисленное деление на константу
Об этом ТС не говорилibiza11 писал(а):обратно в Bin перевести надо.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
-
orinoko
Re: Целочисленное деление на константу
Умножения с дикими числами - это перебор, как по моему, делить "примерно" тоже не подходит. У меня идёт расчёт среднеквадратического значения.

Я написал тип МК, там есть умножитель 8*8=16. А в общем то вопрос решёнесть ли аппаратное умножение
- Gudd-Head
- Друг Кота
- Сообщения: 20092
- Зарегистрирован: Чт сен 18, 2008 12:27:21
- Откуда: Столица Мира Санкт-Петербург
Re: Целочисленное деление на константу
Да ладно... несколько 2-х тактных операций умножения и сложения.orinoko писал(а):Умножения с дикими числами - это перебор
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
-
orinoko
Re: Целочисленное деление на константу
Можно попробовать ради интереса. И сравнить.
Re: Целочисленное деление на константу
При делении 16 битного числа 32х разрядов не хватает, однако.ChipKiller писал(а):PS. если нужно точнее можно так X/200=(X*83886)>>24 ... 24 сдвига конечно делать не надо
И занижает на единицу местами. Вот так точно ((X+1)*83886)>>24
Если с аппаратным умножением делать, то по моим прикидкам 16bit * 24bit = 40bit выльется в 6 умножений 8*8=16 и 22 сложения (8 битных). Если всё на регистрах, то это 34 такта, плюс накладные расходы.
Если не ошибаюсь, то это около 450 тактов получается на 16 мегагерцах.orinoko писал(а):по времени 28 мкс.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
- КРАМ
- Друг Кота
- Сообщения: 25273
- Зарегистрирован: Чт янв 10, 2008 22:01:02
- Откуда: Московская область, Фрязино
Re: Целочисленное деление на константу
И что из этого следует?orinoko писал(а):У меня идёт расчёт среднеквадратического значения.
-
orinoko
Re: Целочисленное деление на константу
Если всё делать в регистрах, то может, причём это очень оптимистично. Но количество регистров, допускаемых для этой операции, не резиновое, поэтому, если будут добавляться операции с памятью...Если с аппаратным умножением делать, то по моим прикидкам 16bit * 24bit = 40bit выльется в 6 умножений 8*8=16 и 22 сложения (8 битных). Если всё на регистрах, то это 34 такта, плюс накладные расходы.
Это было к тому, что предлагалось умножить на ~328У меня идёт расчёт среднеквадратического значения.
И что из этого следует?
Re: Целочисленное деление на константу
Поделить на 200 (точнее на 200.0001907) можно и так:
( X SHR 8 )+( X SHR 10 )+( X SHR 13 )-( X SHR 18 )-( X SHR 20 )-( X SHR 23 )
Понятно, что при реализации все число X сдвигать не надо.
( X SHR 8 )+( X SHR 10 )+( X SHR 13 )-( X SHR 18 )-( X SHR 20 )-( X SHR 23 )
Понятно, что при реализации все число X сдвигать не надо.
Последний раз редактировалось El-Eng Сб апр 20, 2013 09:59:10, всего редактировалось 1 раз.
Like the eyes of a cat in the black and blue...
- ChipKiller
- Сверлит текстолит когтями
- Сообщения: 1163
- Зарегистрирован: Ср янв 05, 2011 16:25:15
Re: Целочисленное деление на константу
... согласен - быстродействие и размер в большей степени "съедят" не умножения а пересылки, но в любом случае будет побыстрее 28 мкс.orinoko писал(а):Если всё делать в регистрах, то может, причём это очень оптимистично. Но количество регистров, допускаемых для этой операции, не резиновое, поэтому, если будут добавляться операции с памятью...
.. ошибка при округлении присутствует все равно. Точность (X*~328)>>16 можно повысить т.е. (X*327,68)=X*(328 - 0.32)=X*328-X*(32*2,56/256)=X*328-X*(81,92/256) и наконец в итоге ((X*328)-(X*82)>>8)>>16.orinoko писал(а):Это было к тому, что предлагалось умножить на ~328
Т.к. (X*328)=(X*0x148)=X<<8+X*0x48 - имеем в итоге 4 умножения и кучу пересылок
- ChipKiller
- Сверлит текстолит когтями
- Сообщения: 1163
- Зарегистрирован: Ср янв 05, 2011 16:25:15
Re: Целочисленное деление на константу
если сдвиг не кратен 8, то двигать придется многоEl-Eng писал(а):Понятно, что при реализации все число X сдвигать не надоКод: Выделить всё
...
...возможно что то упустил, но откуда вместо X, (X+1) не понял....Kavka писал(а):И занижает на единицу местами. Вот так точно ((X+1)*83886)>>24
Re: Целочисленное деление на константу
Не так и много: пять сдвигов двухбайтных чисел, два однобайтного, один SWAP и взять старший бит исходного числа.ChipKiller писал(а):если сдвиг не кратен 8, то двигать придется много
Like the eyes of a cat in the black and blue...


