реклама на сайте
подробности

 
 
3 страниц V  < 1 2 3 >  
Reply to this topicStart new topic
> Вычисления на ATmega88
_Pasha
сообщение Dec 3 2008, 08:55
Сообщение #16


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(n_bogoyavlensky @ Dec 3 2008, 12:26) *
Т. е., просто согласиться с появляющейся ошибкой?

Я ж говорю 256/255 = 1.0039 Точнее - 4 промилле.
Цитата
Но я не знаю как сопрячь WinAVR C и ассемблер

Сишка:
Код
uint8_t n_red,n_green,n_blue;
uint8_t precomputed;
extern void fast_out(void);

Добавляете в проект файл fast_out.S
Код
#include <avr/io.h>
.extern n_red,n_blue,n_green
.extern precomputed

fast_out:
  lds r24,precomputed
  lds r25,n_red
  mul r24,r25
  out OCR0A,r1
  lds r25,n_green
  mul r24,r25
  out OCR0B,r1
  lds r25,n_blue
  sts OCR2A,r1
  ret
// put the global declaration to export function name

.global fast_out


Уже в таком виде должно собраться.
В данном примере precomputed - это Ваше С'
Но, скорее всего, Вам придется эту часть, с предварительными вычислениями тоже в асм внести.
Успехов!

В догонку.
Деление на 255 в данном случае можно заменить делением на 256 и учетом одного исключения:
Код
if (c !=255) a = (b*c)/256; else a=b;

Просьба не воспринимать это как сишный текст smile.gif
Go to the top of the page
 
+Quote Post
koluna
сообщение Dec 3 2008, 09:46
Сообщение #17


Профессионал
*****

Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061



Цитата
В догонку.
Деление на 255 в данном случае можно заменить делением на 256 и учетом одного исключения:
Код
if (c !=255) a = (b*c)/256; else a=b;

Просьба не воспринимать это как сишный текст smile.gif


И как паскалевский, и как ассемблерный... ясен перец smile.gif

За быстрое деление на 255 - всем спасибо.
Работает. Быстро работает smile.gif

Сообщение отредактировал n_bogoyavlensky - Dec 3 2008, 09:47


--------------------
Благодарю заранее!
Go to the top of the page
 
+Quote Post
=GM=
сообщение Dec 3 2008, 11:00
Сообщение #18


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Цитата(Непомнящий Евгений @ Dec 3 2008, 05:26) *
Ну просто это получается эквивалентно C2/256. Просто малость замаскировано smile.gif

Вы не правы, это НЕ эквивалентно C2/256, это примерно эквивалентно C2/257. Судите сами, C2/255 = C2/(65536/257)=С2*257/65536=(С2*257)>>16. А примерно эквивалентно потому, что вы делите на 65536/257=255.0039, а не точно на 255.

Что касается вашей формулы (С2*257) >> 16 =( (С2 <<8) + C2)>>16 = ((C2<<8)>>16) + (C2>>16) = C2>>8 = C2/256, то она неверна. Два слагаемых перекрываются на 8 бит, и меньшее слагаемое нельзя просто отбросить, поскольку при суммировании оно может дать перенос в старший байт, который и будет окончательным результатом.

Вот пример. Пусть С2=0x8899=34969, тогда C2*256=0x889900,
C2*257=C2*256+C2=0x889900+0x8899=0x892199
и, наконец, С=C2*257>>16=0x89=137. Простая проверка: С=34969/255=137.1

По вашей формуле С=С2>>8=0x88=136

Вывод такой. Если хотите поделить на 255, то лучше делить на 255.0039, чем на 256. Всяко точнее будет. Вообще такой подход хорош при делении на константу.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
koluna
сообщение Dec 12 2008, 20:39
Сообщение #19


Профессионал
*****

Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061



Вот ещё одна задача.
Как аналогичным образом целочисленно поделить одно 8-битное число на другое 8-битное число?
Более конкретно - деление на 10.


--------------------
Благодарю заранее!
Go to the top of the page
 
+Quote Post
singlskv
сообщение Dec 12 2008, 21:13
Сообщение #20


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Дык все точно так же,
умножте на 26(~256/10) или на 6554(~65536/10) ну и если нужно скоректируйте...
Go to the top of the page
 
+Quote Post
Александр Куличо...
сообщение Dec 12 2008, 23:29
Сообщение #21


Местный
***

Группа: Свой
Сообщений: 256
Регистрация: 6-03-06
Из: Украина, г. Винница
Пользователь №: 15 017



Цитата(n_bogoyavlensky @ Dec 12 2008, 22:39) *
Вот ещё одна задача.
Как аналогичным образом целочисленно поделить одно 8-битное число на другое 8-битное число?
Более конкретно - деление на 10.


Для диапазона A=[0..255): (unsigned char)(А+1)*51>>9

Для диапазона A=[0..255] ((unsigned char)(А*51) + 51)>>9

или на асме соответственно
Код
    ldi    temp,51
    inc    A    
    mul    A,temp
    lsr    R1

и
    ldi    temp,51
    mul    A,temp
    add    R0,temp
    adc    R1,zero
    lsr    R1
Go to the top of the page
 
+Quote Post
koluna
сообщение Dec 13 2008, 11:33
Сообщение #22


Профессионал
*****

Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061



Цитата
Для диапазона A=[0..255): (unsigned char)(А+1)*51>>9

Для диапазона A=[0..255] ((unsigned char)(А*51) + 51)>>9


Спасибо! smile.gif
Кстати, откуда вы с такой лёгкостью извлекаете эти волшебные выражения? smile.gif
Они где-то перечислены или их можно достаточно просто придумать самому? Каков принцип?

А для диапазона A=[0..65535]?

Цитата(singlskv @ Dec 13 2008, 01:13) *
Дык все точно так же,
умножте на 26(~256/10) или на 6554(~65536/10) ну и если нужно скоректируйте...



Всмысле?
Что умножить и как скорректировать?


--------------------
Благодарю заранее!
Go to the top of the page
 
+Quote Post
singlskv
сообщение Dec 13 2008, 12:06
Сообщение #23


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(n_bogoyavlensky @ Dec 13 2008, 14:33) *
Всмысле?
Что умножить и как скорректировать?

Именно так как в посте №21

51 ~= 256 * 2 / 10

+ 51 корректировка
Go to the top of the page
 
+Quote Post
koluna
сообщение Dec 13 2008, 12:16
Сообщение #24


Профессионал
*****

Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061



Цитата(singlskv @ Dec 13 2008, 16:06) *
Именно так как в посте №21

51 ~= 256 * 2 / 10

+ 51 корректировка


Всё равно пока не пойму каков принцип? sad.gif


--------------------
Благодарю заранее!
Go to the top of the page
 
+Quote Post
ae_
сообщение Dec 13 2008, 12:56
Сообщение #25


Участник
***

Группа: Свой
Сообщений: 462
Регистрация: 2-04-07
Из: Иркутск
Пользователь №: 26 695



x/10 = x*(1/10) = x*(205/2048) = (x*205)>>11
x/10 = x*(1/10) = x*(52429/524288) = (x*52429)>>19
Go to the top of the page
 
+Quote Post
xemul
сообщение Dec 13 2008, 12:56
Сообщение #26



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(n_bogoyavlensky @ Dec 13 2008, 15:16) *
Всё равно пока не пойму каков принцип? sad.gif

x/10 ~= x*51/512 = (x*51)>>9
или x/10 ~= x*26/256 = (x*26)>>8
или ...
подберите что-нибудь, устраивающее по точности.
Для корректного целочисленного округления все-таки д.б. ((x*51)+51/2)>>9 ~= ((x*51)+26)>>9
Go to the top of the page
 
+Quote Post
SSerge
сообщение Dec 13 2008, 13:00
Сообщение #27


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(n_bogoyavlensky @ Dec 13 2008, 18:16) *
Всё равно пока не пойму каков принцип? sad.gif

Дык, a/b преобразуется в a*(N/b) / N, при подходящем выборе N (степень двойки) выражение N/b вычисляется ещё на этапе компиляции, а умножение и последующее деление на N (сдвигами или отбрасыванием младших байтов результата) выполняется быстрее чем просто деление на b, особенно при наличии аппаратного умножителя.

Добавлю ещё, что если b не константа то подобный метод тоже срабатывает - есть достаточно эффективные алгоритмы вычисления 1/b (или N/b). Всё из-за того, что аппаратный делитель выходит заметно сложнее умножителя, вот на нём и экономят, даже в суперкомпьютерах.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
koluna
сообщение Dec 13 2008, 18:34
Сообщение #28


Профессионал
*****

Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061



Цитата(xemul @ Dec 13 2008, 16:56) *
x/10 ~= x*51/512 = (x*51)>>9
или x/10 ~= x*26/256 = (x*26)>>8
или ...
подберите что-нибудь, устраивающее по точности.
Для корректного целочисленного округления все-таки д.б. ((x*51)+51/2)>>9 ~= ((x*51)+26)>>9


С делением теперь понятно. Спасибо smile.gif
С округлением до ближайшего целого не понятно...


--------------------
Благодарю заранее!
Go to the top of the page
 
+Quote Post
xemul
сообщение Dec 13 2008, 20:41
Сообщение #29



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(n_bogoyavlensky @ Dec 13 2008, 21:34) *
С делением теперь понятно. Спасибо smile.gif
С округлением до ближайшего целого не понятно...

Спасибо, был неправ. Вместо
((x*51) + 51/2) >> 9 ~= ((x*51)+26)>>9
читать
((x*51) + 1<<8) >> 9 = (x*51)>>9 + 0.5

Правила округления до целого предполагают, что (н-р, применительно к десятичной системе счисления) если дробная часть = [0.0..0.4(9)], то число округляется "вниз" (дробная часть просто отбрасывается), если дробная часть = [0.5..0.9(9)], то число округляется "вверх" (дробная часть отбрасывается, к целой части добавляется 1).
Контроллер при целочисленных операциях может только отбросить дробную часть. Чтобы заставить его округлять "по-человечески", нужно перед целочисленными операциями с потерей точности (типа деление/сдвиг) добавить к операнду половину разряда, который станет младшим значащим разрядом после выполнения операции (== половину делителя).

Округляем до целого в десятичной системе:
половина значащего разряда = 0.5
trunc(31.49 + 0.5) = 31
trunc(31.5 + 0.5) = 32

Округляем до целого в двоичной системе:
пусть 0b10100101 (= 165 дес.) хочется сдвинуть вправо на 3 разряда
половина делителя = 1 << (3 - 1) = 0b100
0b10100101 >> 3 = 0b10100 (= 20 дес.)
(0b10100101 + 0b100) >> 3 = 0b10101 (= 21 дес.)
165/8 = 20.625 ~= 21
Go to the top of the page
 
+Quote Post
singlskv
сообщение Dec 13 2008, 21:33
Сообщение #30


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(xemul @ Dec 13 2008, 23:41) *
Спасибо, был неправ. Вместо
((x*51) + 51/2) >> 9 ~= ((x*51)+26)>>9
читать
((x*51) + 1<<8) >> 9 = (x*51)>>9 + 0.5

на самом деле рассчет коррекции проще всего делать так:
- пример с домножением на 51
- пусть коррекция = A, те ((x * 51) + A) / 512 ~= x / 10
- тогда д.б.:
1.) 0 * 51 +A >= 0
2.) 9 * 51 +A < 1 * 512
3.) 10 * 51 + A >= 1 * 512
4.)250 * 51 + A >= 25 * 512
5.)255 * 51 + A < 26 * 512
- преобразуем
1.) A >= 0
2.) A < 53
3.) A >= 2
4.) A >= 50
5.) A < 307

-итого: 50<= A < 53

то есть нам подойдут 50, 51, 52

выбор чисел 0, 9, 10, 250, 255 надеюсь понятен
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st June 2025 - 04:10
Рейтинг@Mail.ru


Страница сгенерированна за 0.01478 секунд с 7
ELECTRONIX ©2004-2016