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

 
 
2 страниц V  < 1 2  
Reply to this topicStart new topic
> Применение целочисленной арифметики
umup
сообщение Feb 7 2007, 19:25
Сообщение #16


Местный
***

Группа: Свой
Сообщений: 226
Регистрация: 2-06-06
Пользователь №: 17 720



Яrik
Вот сказали бы это сразу и не было бы столько споров, а то уже начали приводить примеры которые на контроллерах почти не встречаются (типа 0.000076538435*25484135е3), в большинстве случаев достаточно 16 или 32 битных целых с фиксированной точкой.
Для вашего случая достаточно 2х сдвигов вправо (*256 - это сдвиг влево на 8 разрядов, /1023 - почти сдвиг вправо на 10 разрядов, итого на 2 вправо), и не нужно никаких делений/умножений. Точку между цифрами, надеюсь, сами нарисуете ?
А для перевода чисел в строку есть стандартная функция кажется itoa()

Сообщение отредактировал umup - Feb 7 2007, 19:30
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Feb 8 2007, 00:51
Сообщение #17


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(umup @ Feb 7 2007, 20:25) *
Яrik
Вот сказали бы это сразу и не было бы столько споров, а то уже начали приводить примеры которые на контроллерах почти не встречаются (типа 0.000076538435*25484135е3), в большинстве случаев достаточно 16 или 32 битных целых с фиксированной точкой.
Для вашего случая достаточно 2х сдвигов вправо (*256 - это сдвиг влево на 8 разрядов, /1023 - почти сдвиг вправо на 10 разрядов, итого на 2 вправо), и не нужно никаких делений/умножений. Точку между цифрами, надеюсь, сами нарисуете ?
А для перевода чисел в строку есть стандартная функция кажется itoa()


Для таких случаев бывает формула не очень подходит. Используется бывает коррекция. Если наблюдается нелинейность. Тогда табличным методом.

Если хотите всётаки полностью по формуле, то лучше целочисленным методом. Умножение на 256 Вам сказали как (сдвигов конечно не надо, просто результат читаете в байт 1 и 2 (а байт 0 - обнуляете) а деление к примеру так

Код
;========================================================================
; Поделить 32 бита (ddt:ddl) на 32 бита (dv3:dv0).
;------------------------------------------------------------------------
; Входные  регистры: ddt:ddl,dv3:dv0
; Выходные регистры: ddt:ddl(частное), w3:w2:wh:wl(остаток)
; Портятся регистры: tmp

div32:
    clrq    w                    ; очистить остаток и перенос
    ldi        tmp,33                ; инициализировать счетчик цикла
du_1:
    rolq    dd                    ; делимое/результат сдвинуть влево
    dec        tmp                    ; умньшить на единицу счетчик цикла
    brne    du_2                ; переход, если не ноль
    ret                            ; выйти
du_2:
    rolq    w                    ; остаток сдвинуть влево
    subq    w,dv                ; остаток= остаток - делитель
    brcc    du_3                ; если результат < 0
    addq    w,dv                ; восстановить остаток
    clc                            ; сбросить перенос для формирования результата
    rjmp    du_1                ; иначе
du_3:
    sec                            ; установить перенос для формирования результата
    rjmp    du_1                ; вернуться назад

где


;****************************************************************
;*   Команда SUB для 32-ух битных чисел в регистрах.             *
;****************************************************************

.macro        subq                ; Два параметра "Имя регистров"

    sub        @0l,@1l                ; загрузить регистр 0
    sbc        @0h,@1h                ; загрузить регистр 1
    sbc        @0d,@1d                ; загрузить регистр 2
    sbc        @0t,@1t                ; загрузить регистр 3
.endm

;****************************************************************
;*   Команда ADD для 32-ух битных чисел в регистрах.             *
;****************************************************************

.macro        addq                ; Два параметра "Имя регистров"

    add        @0l,@1l                ; загрузить регистр 0
    adc        @0h,@1h                ; загрузить регистр 1
    adc        @0d,@1d                ; загрузить регистр 2
    adc        @0t,@1t            ; загрузить регистр 3
.endm    

;****************************************************************
;*   Команда CLR для 32-ух битных чисел в регистрах.             *
;****************************************************************

.macro        clrq                ; один параметр "Имя регистров"

    clr        @0l                    ; загрузить регистр 0
    clr        @0h                    ; загрузить регистр 1
    clr        @0d                    ; загрузить регистр 2
    clr        @0t                    ; загрузить регистр 3
.endm

;****************************************************************
;*   Команда ROL для 32-ух битных чисел в регистрах.             *
;****************************************************************

.macro        rolq                ; один параметр "Имя регистров"

    rol        @0l                    ; загрузить регистр 0
    rol        @0h                    ; загрузить регистр 1
    rol        @0d                    ; загрузить регистр 2
    rol        @0t                    ; загрузить регистр 3
.endm

;****************************************************************
;*   Команда LD для 32-ух битных чисел в регистрах.                 *
;****************************************************************

.macro        ldq                    ; Два параметра "Имя регистров" и "параметр".

    ld        @0l,@1                ; загрузить регистр 0
    ld        @0h,@1                ; загрузить регистр 1
    ld        @0d,@1                ; загрузить регистр 2
    ld        @0t,@1                ; загрузить регистр 3
.endm

;****************************************************************
;*   Команда ST для 32-ух битных чисел в регистрах.                 *
;****************************************************************

.macro        stq                    ; Два параметра "Имя регистров" и "параметр".

    st        @0,@1l                ; загрузить регистр 0
    st        @0,@1h                ; загрузить регистр 1
    st        @0,@1d                ; загрузить регистр 2
    st        @0,@1t                ; загрузить регистр 3
.endm
Go to the top of the page
 
+Quote Post
Яrik
сообщение Feb 8 2007, 11:27
Сообщение #18


Частый гость
**

Группа: Новичок
Сообщений: 110
Регистрация: 8-01-07
Из: Украина
Пользователь №: 24 216



Цитата
Для таких случаев бывает формула не очень подходит. Используется бывает коррекция. Если наблюдается нелинейность. Тогда табличным методом.

Если хотите всётаки полностью по формуле, то лучше целочисленным методом. Умножение на 256 Вам сказали как (сдвигов конечно не надо, просто результат читаете в байт 1 и 2 (а байт 0 - обнуляете) а деление к примеру так

Спасибо! А нет ли у Вас примера на СИ, потму что попытка сделать асеммблерную вставку в CodeVisionAvr у меня не увенчалась успехом.
Go to the top of the page
 
+Quote Post
mse
сообщение Feb 8 2007, 11:49
Сообщение #19


Знающий
****

Группа: Свой
Сообщений: 709
Регистрация: 3-05-05
Пользователь №: 4 693



Цитата(umup @ Feb 7 2007, 19:25) *
Яrik
Вот сказали бы это сразу и не было бы столько споров, а то уже начали приводить примеры которые на контроллерах почти не встречаются (типа 0.000076538435*25484135е3), в большинстве случаев достаточно 16 или 32 битных целых с фиксированной точкой.

Вот в том-то и дело, что в ряде случаев, плывучка с 8-16 битной мантиссой и 8-бит экспонентой уделает и по скорости, и по динамике 32 битную целочисленку. Повторюсь. Это актуально для 8-битников. И чем горбатее 8-битник в плане арифметики, тем актуальнее. Для АРМа, например, смысла в плывучке реально нет вообще.
А что встречается, а что почти не встречается, так то смотря какие задачи кем решаются. Кое кто из плывучки мож и не вылазит.
Go to the top of the page
 
+Quote Post
=GM=
сообщение Feb 8 2007, 19:04
Сообщение #20


Ambidexter
*****

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



To SasaVitebsk. I've rearranged your code a bit. It looks better and quicker now.
Sorry for english text, this bl@$dy hell keyboard..

Код
;========================================
; Поделить 32 бита (ddt:ddl) на 32 бита (dv3:dv0).
;------------------------------------------------------------------------
; Входные  регистры: ddt:ddl,dv3:dv0
; Выходные регистры: ddt:ddl(частное), w3:w2:wh:wl(остаток)
; Портятся регистры: tmp

div32:       clrq         w                   ; очистить остаток и перенос
             ldi          tmp,32              ; инициализировать счетчик цикла
du1:         subq         w,dv                ; остаток= остаток - делитель
             brcc         du2                 ; если результат < 0
             addq         w,dv                ; восстановить остаток
du2:         rolq         dd                  ; делимое/результат сдвинуть влево
             rolq         w                   ; остаток сдвинуть влево
             dec          tmp                 ; умeньшить на единицу счетчик цикла
             brne         du1                 ; переход, если не ноль
             comq         dd                  ; invert the quotient
             ret                              ; выйти



--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
AndreyKeil
сообщение Feb 8 2007, 21:27
Сообщение #21


Частый гость
**

Группа: Свой
Сообщений: 96
Регистрация: 16-11-05
Из: г.Екатеринбург
Пользователь №: 10 930



Извиняюсь, если мой вопрос не в тему, скажите алгоритм преобразования целого числа в формат плавающей точки и наоборот - плавающего в целое?
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Feb 8 2007, 21:30
Сообщение #22


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(Яrik @ Feb 8 2007, 12:27) *
Спасибо! А нет ли у Вас примера на СИ, потму что попытка сделать асеммблерную вставку в CodeVisionAvr у меня не увенчалась успехом.


Ну Вы и даёте. smile.gif А на си это выглядит в точности как Вы написали.

Res=adc_res*256/1023;
Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 8 2007, 22:16
Сообщение #23


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Яrik @ Feb 6 2007, 21:25) *
Да, да какраз это... Я думал, что используя целочисленную арифметику удастся уменьшить объем занимаемой програмой. Но теперь понял, что ошибался.
Я питался выводить на LCD результат измереного АЦП напряжения. В результате использования команды printf, объем памяти занимаемой программой сотавил 50% имеющейся в ATmega8.
Может кто поделится своими наработками? Зарание благодарю.

Дык это не плавучая арифметика столько памяти жрет, а сама функция printf! excl.gif Уже неоднократно и многими подчеркивался тот факт, что printf и sprintf требуют для работы от сотни байт до 1,5 килоБайт стековой памяти, то бишь ОЗУ. Так что советую оставить плавучку в покое, а лишь написать собственную функцию перевода числа в символьное представление.
Когда-то делал устройство, поддерживающее пакетную связь по RS-485, обработку клавиатуры и вывод на два четырехсимвольных семисегментника двух дробных чисел. Также долго мучал printf, пока не понял, что на имеющихся 256 байтах ОЗУ нельзя ее пользовать. Для вывода даже одного числа с фиксированной точкой и двумя знаками после запятой printf использовал больше 100 байт стека. А в распоряжении было всего около 50 байт smile.gif В результата написал свою функцию типа поразрядного деления на степень 10, которая использовала не более 8 байт на стеке. За скоростью вычислений в таких случаях гнаться не нужно. Потому что обновлять информацию на индикаторе чаще 3 раз в секунду нет никакого смысла. Во-первых, человеческий глаз инертен. Во-вторых, наблюдателю нужно еще время чтобы осознать наблюдаемое число. Так что, используйте на здоровье плавучку и не используйте printf. wink.gif
Go to the top of the page
 
+Quote Post
mse
сообщение Feb 8 2007, 23:01
Сообщение #24


Знающий
****

Группа: Свой
Сообщений: 709
Регистрация: 3-05-05
Пользователь №: 4 693



Цитата(AndreyKeil @ Feb 8 2007, 21:27) *
Извиняюсь, если мой вопрос не в тему, скажите алгоритм преобразования целого числа в формат плавающей точки и наоборот - плавающего в целое?

Будете смеяться, но тупо до безобразия. Не буду рассказывать про форматы ИЕЕЕ. В ембеддед приложениях смысла в ихней упаковке нет никакого. Если што, сами найдёте. А общий смысл такой: целое число нужно привести к формату 1,хх...хх. Это называецца мантисса. Что соответствует диапазону 111...11 до 100..00. Или, в десятичном эквиваленте, от 1,9..99 до 1. И в комплект дать експоненту, т.е. тупой множитель вида 2^N, где N, я, для удобства, принимаю как ±0х3f. Ехп содержится в отдельном байте. Старший бит которого является знаком числа в целом. Таким образом плавучее число прецтавляет из себя такую конструкцию: Мант*(2^Ехп). Нуль, когда в мантиссе нуль. Это ессно.

Пример. Вначале имеете число, пусть 8р. И ему в соотв. ставим експоненту. Вначале=7. Бо это номер старшево бита.
Далее, сдвигаем влево и соотвецтвенно декрементируем ехпоненту. До тех пор, пока старший разряд не станет =1. Или не кончится ехпонента. Если подвинули 7 раз, а 1 в старшем разряде нет, тоды имеем нуль. Судьба.
Пример 0х80 -> 0х80 мантисса и 7-експонента. Проверяем: 0х80 это 1,0. Множим его на 2^7, получаем 128. Или 0х80 целочисленно.
0х01-> 0х80мантисса и 0-експонента. Проверяем:0х80 это1,0. Множим его на 2^0, получаем 1. Оба-на, совпадло!
Плывучее в целое - строго наоборот. Сдвигаем на число разрядов в ехп, предварительно отняв от неё номер старшево бита мантиссы. Если ехп получилась отриццательная, то вправо. Если положительная, то влево. Т.е. результат может быть сильно больше исходной мантиссы! Или наоборот, 0.
Пример. М=0х80, Е=0х7. Тогда отымем от Е 0х7. Получим нуль. Сдвинем 0х80 на нуль влево, получим 0х80. Опять совпадло! Чюдо!
Пример нумер2: М=0х80, Е=0х0. Отымаем от Е 0х7. Получаем Е=-7. Помним, что старший бит ехп - знак числа в целом. Для удобства его упаковывают в Е на время хранения. Но в работе он должен храниться отдельно для упрощения арифметики. Но отсюда вытекает проблема: в результате любых манипуляций Е должна находиться в пределах ±0х3F, или 0x3f...0xc0. Если вылетает за, значить у нас произошло исключение - результат стал равен ±бесконечность или ± не-число. Что тут делать - думайте сами. Итак, число 0х80 сдвигаем на -7 разрядов влево, т.е. вправо. Получаем 0х1. Совпало. Кто бы сомневался.
Go to the top of the page
 
+Quote Post
add
сообщение Feb 9 2007, 12:48
Сообщение #25


Местный
***

Группа: Свой
Сообщений: 345
Регистрация: 10-10-05
Пользователь №: 9 459



mse, немогли бы Вы пояснитьследующее, если к примеру взять число 56 (0b00111000) после двух смещений влево получили 224 (0b11100000) и E=5. Это как считать? 1,96*2^5 в десятичке? несовсем понятно?!
заранее пасиба за ответ.


--------------------
Если задачу можно решить, то не надо тревожиться. А если нельзя решить, то тревожиться бесполезно.
Go to the top of the page
 
+Quote Post
mse
сообщение Feb 9 2007, 13:13
Сообщение #26


Знающий
****

Группа: Свой
Сообщений: 709
Регистрация: 3-05-05
Пользователь №: 4 693



Цитата(add @ Feb 9 2007, 12:48) *
mse, немогли бы Вы пояснитьследующее, если к примеру взять число 56 (0b00111000) после двух смещений влево получили 224 (0b11100000) и E=5. Это как считать? 1,96*2^5 в десятичке? несовсем понятно?!
заранее пасиба за ответ.

Всё верно. ;О) тока интертрепаццыя не та. 0хе0/2^7(!!!)=1,75. 1,75*2^5=56
Go to the top of the page
 
+Quote Post
Яrik
сообщение Feb 10 2007, 00:15
Сообщение #27


Частый гость
**

Группа: Новичок
Сообщений: 110
Регистрация: 8-01-07
Из: Украина
Пользователь №: 24 216



Цитата
Дык это не плавучая арифметика столько памяти жрет, а сама функция printf! Уже неоднократно и многими подчеркивался тот факт, что printf и sprintf требуют для работы от сотни байт до 1,5 килоБайт стековой памяти, то бишь ОЗУ. Так что советую оставить плавучку в покое, а лишь написать собственную функцию перевода числа в символьное представление.
Когда-то делал устройство, поддерживающее пакетную связь по RS-485, обработку клавиатуры и вывод на два четырехсимвольных семисегментника двух дробных чисел. Также долго мучал printf, пока не понял, что на имеющихся 256 байтах ОЗУ нельзя ее пользовать. Для вывода даже одного числа с фиксированной точкой и двумя знаками после запятой printf использовал больше 100 байт стека. А в распоряжении было всего около 50 байт В результата написал свою функцию типа поразрядного деления на степень 10, которая использовала не более 8 байт на стеке. За скоростью вычислений в таких случаях гнаться не нужно. Потому что обновлять информацию на индикаторе чаще 3 раз в секунду нет никакого смысла. Во-первых, человеческий глаз инертен. Во-вторых, наблюдателю нужно еще время чтобы осознать наблюдаемое число. Так что, используйте на здоровье плавучку и не используйте printf.


Понял. А не могли бы Вы привести пример или алгоритм собственно самого переобразования в текст? Я как то уже спрашивал на форуме по этому поводу, но неполучил врозумительного ответа. Спасибо.
Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 10 2007, 01:16
Сообщение #28


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Яrik @ Feb 10 2007, 02:15) *
Понял. А не могли бы Вы привести пример или алгоритм собственно самого переобразования в текст? Я как то уже спрашивал на форуме по этому поводу, но неполучил врозумительного ответа. Спасибо.

Вот из "пустыни" целая ветка примерно на эту же тему http://caxapa.ru/79812.html?todo=full
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 18th July 2025 - 14:17
Рейтинг@Mail.ru


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