Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.51/57: Рейтинг темы: голосов - 57, средняя оценка - 4.51
0 / 0 / 0
Регистрация: 23.05.2010
Сообщений: 4

Умножение дробных чисел испольуя asm

20.12.2013, 11:31. Показов 10748. Ответов 15
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Как умножить 2 дробных числа на cortex-m3, с округленным целым результатом?
Например
78,3*45,4 = 3554,8 ~ 3555
Если умножать только целые числа получается большая погрешность..
78*45=3510
3510/3555~1%.
При следующих итерациях эта погрешность накапливается и становится достаточно большой.
Как из ситуации выйти?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
20.12.2013, 11:31
Ответы с готовыми решениями:

Умножение дробных чисел
Народ, кто подскажет что творит комамнда fmul, т.е. как умножаются дробные числа в асме? В Естифееве прочитал и не могу понять...

Умножение дробных чисел в асме
Связался с этим делом, покурил апнот200. Но тока он чето не работает, считает и выдает какую-то лажу. Более менее считает числа с одним...

AT90S1200. Умножение 4-х разрядных чисел на ASM
Здравствуйте! Столкнулся с проблемой. Нужно написать ПО на ассемблере (умножение 4-разрядных чисел в ВСD-формате), микроконтроллер...

15
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 222
20.12.2013, 12:28
А так нельзя? 783*454=355482
0
0 / 0 / 0
Регистрация: 23.05.2010
Сообщений: 4
20.12.2013, 14:09
Цитата Сообщение от okt
А так нельзя? 783*454=355482
Так можно... НО!! Перед следующим умножением нужно отбросить 2 последних разряда, т.е разделить на 100! Как-то использовать операцию деления не хочется, т.к. она за долгие 7 тактов выполняется. А если делить сдвигом вправо, то разделить можно только на 64 или 128.
0
1 / 1 / 0
Регистрация: 11.01.2013
Сообщений: 5,479
20.12.2013, 14:33
Цитата Сообщение от wypuk
Перед следующим умножением нужно отбросить 2 последних разряда, т.е разделить на 100!
Более того, перед делением надо добавлять к делимому половину делителя (100/2=50). Иначе быстро наберётся такая же неточность, от которой Вы хотите избавиться.

А вообще - почитайте про арифметику с фиксированной точкой. Оно как раз об этом. Действия производятся с числами, смещёнными на фиксированное количество разрядов, и только при выводе на дисплей/UART/файл/etc делается форматирование с восстановлением (визуально) дробной части.
0
1 / 1 / 0
Регистрация: 09.02.2012
Сообщений: 693
20.12.2013, 14:36
А здесь и стала дилемма. Или делить на 100 или понижать точность. На AVRках я весь алгоритм умножал на 100 и уже конечный результат делил.
0
1 / 1 / 0
Регистрация: 11.01.2013
Сообщений: 5,479
20.12.2013, 14:38
Цитата Сообщение от wypuk
использовать операцию деления не хочется, т.к. она за долгие 7 тактов выполняется. А если делить сдвигом вправо, то разделить можно только на 64 или 128.
Семь тактов на частоте 72 МГц - то есть ~100 наносекунд - это долго? ;-)

Сдвигом вправо, кстати, тоже можно делить, просто не привязывайтесь к десятичной форме представления числа, работайте в двоичной (восьмиричной/шестнадцатиричной, не суть). Тогда быстрые сдвиги будут работать. В десятичный формат переведёте уже только при окончательном выводе результата пользователю, как я писал выше.
0
0 / 0 / 0
Регистрация: 23.05.2010
Сообщений: 4
20.12.2013, 15:01
Цитата Сообщение от OtyxPM
Семь тактов на частоте 72 МГц - то есть ~100 наносекунд - это долго? ;-)
Если рассматривать под таким углом - то конечно это мелочь, но если эта операция будет повторяться многократно... полное время работы алгоритма может существенно увеличиться. Я же не просто так с ассемблером вожусь.
Цитата Сообщение от OtyxPM
Сдвигом вправо, кстати, тоже можно делить, просто не привязывайтесь к десятичной форме представления числа, работайте в двоичной (восьмиричной/шестнадцатиричной, не суть).
В этом вся загвоздка, у меня пока сложности с восприятием такой арифметики. Придется вникать в арифметику с фиксированной точкой.
0
1 / 1 / 0
Регистрация: 11.01.2013
Сообщений: 5,479
20.12.2013, 15:30
Цитата Сообщение от wypuk
у меня пока сложности с восприятием такой арифметики. Придется вникать в арифметику с фиксированной точкой.
Ну вот смотрите: какой-нибудь датчик (скажем, популярный цифровой термометр DS18B20) выдаёт температуру в двоичном виде с дробями. Это длинное число, и в некоторой (фиксированной) позиции проходит граница между целой и дробной частью. Датчик выдаёт значение уже смещённое (в данном случае на 4 двоичных разряда, или один шестнадцатиричный).
0x0010 - целая единица;
0x0008 - половина от целой единицы = восемь шестнадцатых, то есть 1/2;
0x0011 - целая единица и одна шестнадцатая;
0x0018 - целая единица и восемь шестнадцатых, то есть полтора;
С этими числами можно делать любые арифметические действия, как обычно, а для деления использовать сдвиг вправо.
Как-то так.
0
0 / 0 / 0
Регистрация: 23.05.2012
Сообщений: 214
20.12.2013, 17:05
Это называются числа с фиксированной запятой.
обычно 16битные делятся на 8бит целое 8бит дробная часть
32битное 16 целое 16 дробное.
Операции над ними делают обычными целочисленными командами.
0
0 / 0 / 0
Регистрация: 23.05.2010
Сообщений: 4
20.12.2013, 17:53
Я попробовал перемножить два произвольных числа 1973*0,583185... Размерность дробной части брал 16 бит. Получилось вот что:
(вверху результат выданный калькулятором)


Это имелось ввиду?
т.е. на процессоре мне нужно:
Code
1
2
3
4
MOV   R1, #1973                   ; Целое множимое
LSL   R1, R1, #16                 ; Сдвигаем его влево на 16 бит
MOV   R2, #32219                  ; Дробный множитель 32219/65535 = 0,583185
SMULL R3, R4, R1, R2              ; В R4 целый результат, В R3 дробная часть (в старших 16 битах)
Это справедливо и для знаковых чисел? Подводных камней тут нет никаких?
0
1 / 1 / 0
Регистрация: 11.01.2013
Сообщений: 5,479
20.12.2013, 20:04
Цитата Сообщение от wypuk
Я попробовал перемножить два произвольных числа 1973*0,583185... Размерность дробной части брал 16 бит. Получилось вот что
... ...
Это справедливо и для знаковых чисел? Подводных камней тут нет никаких?
Да никаких. Все компьютеры так работают же. Только для нас, homo sapiensов, в десятичный вид переводят :-)

Для чисел со знаком используйте соответственно знаковые операции (для сложения-вычитания иногда можно обойтись и беззнаковыми).
Не забывайте про такой баланс: чем больше бит в дробной части, тем меньше их в целой. Выбор соотношения размеров целой и дробной частей в арифметике с фиксированной точкой (то есть выбор позиции этой самой точки) зависит от потребностей алгоритма.

Учитывайте, что знак заберёт один бит от 32-хбитного числа. Если все операции беззнаковые - можно позволить себе чуть бОльшую точность.
0
1 / 1 / 0
Регистрация: 11.01.2013
Сообщений: 5,479
20.12.2013, 20:11
Цитата Сообщение от wypuk
Код:
MOV R1, #1973 ; Целое множимое
LSL R1, R1, #16 ; Сдвигаем его влево на 16 бит
MOV R2, #32219 ; Дробный множитель 32219/65535 = 0,583185
SMULL R3, R4, R1, R2 ; В R4 целый результат, В R3 дробная часть (в старших 16 битах)Обратите внимание на этот пример, он замечателен тем, что у первого операнда сдвиг можно было не делать. В подпрограммах, ответственных за максимальную точность и скорость вычислений, можно вручную "подпилить" такие особенности.

А в менее чувствительных кусках кода или в коде, где не известны заранее особенности операндов, придётся забивать в алгоритм какой-то компромисс типа 16+16 бит или 24+8 и т.п.
0
0 / 0 / 0
Регистрация: 23.05.2010
Сообщений: 4
20.12.2013, 22:10
Цитата Сообщение от OtyxPM
Цитата Сообщение от wypuk
Код:
MOV R1, #1973 ; Целое множимое
LSL R1, R1, #16 ; Сдвигаем его влево на 16 бит
MOV R2, #32219 ; Дробный множитель 32219/65535 = 0,583185
SMULL R3, R4, R1, R2 ; В R4 целый результат, В R3 дробная часть (в старших 16 битах)Обратите внимание на этот пример, он замечателен тем, что у первого операнда сдвиг можно было не делать. В подпрограммах, ответственных за максимальную точность и скорость вычислений, можно вручную "подпилить" такие особенности.

А в менее чувствительных кусках кода или в коде, где не известны заранее особенности операндов, придётся забивать в алгоритм какой-то компромисс типа 16+16 бит или 24+8 и т.п.
Спасибо тебе за подсказки! Я с этим делом впринципе разобрался. Все сводится к тому, что при умножении нужно запятую под запятой размещать - прям как в первом классе учили)))
В приведенном коде разрядность дробной части я выбрал 16 только потому, что удобно отсекать целую часть, и точность вычислений до единицы меня устраивает (даже немного точнее получается). И в принципе не должно переполнений возникнуть (разрядность целой части 12 бит - с АЦП).
0
m16
20.12.2013, 23:10
Цитата Сообщение от wypuk
Цитата Сообщение от okt
А так нельзя? 783*454=355482
Перед следующим умножением нужно отбросить 2 последних разряда, т.е разделить на 100!
перед вычислениями нужно привести все константы и переменные к одному порядку.
и пользуем целочисленку на ура. если результат выводим на дисплей , то запятой приводим результат к ранее принятому порядку.
поясню - понадобилось мне посчитать полином :
Code
1
2
3
4
5
6
Sr= S  -  (k1 +  k2*S  -  k3*S^2  +  k4*S^3)*(T - 20)
где
k1=0,1588500
k2=0,0110484
k3=0,0001373
k4=0,0000003
мне нужен был результат с точностью два знака после запятой. после приведения порядков (а это удобно делать в экселе) формула приобрела вменяемый целочисленный вид:
Code
1
2
3
4
5
6
Sr= S  -  (k1  * 100   +  k2*S *10 +  k4*S^3/10   -  k3*S^2  )*( T - 200 )  /   1000000000
где
k1=1588500
k2=110484
k3=1373
k4=3
собсно само вычисление на макроассемблере AVR :
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
;**********************************************************
;      Somstant
;**********************************************************
.equ   k1   = 158850330   // 977DD1A
.equ   k2   = 1104840      // 0x10DBC8
.equ   k3   = 1373      // 0x55D
.equ   k4   = 3
.equ   kp1   = 10
.equ   kp2   = 1000000000   // 0x3B9ACA00
.equ   kt   = 200      // 0xC8
;**********************************************************
;   S  -  (k1 + k2*spt + k4*spt^3/kp1  -  k3*spt^2 )*( temper - kt )  /   kp2
;**********************************************************
;      Data memory
;**********************************************************
.dseg
spt_curr:      .byte   2
spt_20:      .byte   2
.cseg
;**********************************************************
;      Macros
;**********************************************************
.macro   summary
add_d   dC, @1
adc_w   D0, @0         // pre set D1 = 0
.endm
;**********************************************************
test_calc_sprt:   ldi_w      E0, 30
sts_w      spt_curr, E0
ldi_w      E0, 50
sts_w      temper, E0
calc_sprt:   clr_w      D0
..........................................
;   k1
ldi_d      dE, k1
mov_d      dC, dE      // summary= k1
..........................................
;   k2*spt
ldi_d      dH, k2
lds_w      E0, spt_curr
mul_d_w            //  G0 : dF = dH * E0
summary      G0, dF      // summary= k1 + k2*sprt
..........................................
;   sprt^2
mov_w      E1, E0
mul_w            // dF = E1 * E0
push_d      dF      // story  sprt^2
..........................................
;   sprt^3
mov_d      dH, dF
mul_d_w            //  G0 : dF = dH * E0//  G0:dF = sprt^3
..........................................
;   sprt^3*k4
ldi      tmpA, k4
mov_d      dH, dF
mul_d_b            //  G0 : dF = dH * tmpA
..........................................
;   sprt^3*k4/kp1
ldi      tmpA, kp1
div_wd_b            //   G0 : dF = G0 : dF  /  E0l
 
summary      G0, dF      // summary  = k1 + k2*spt + sprt^3*k4/kp1
..........................................
;   k3*spt^2
ldi_w      E0, k3
pop_d      dH      //  dH = sprt^2
mul_d_w            //  G0 : dF = dH * E0
sub_d      dC, dF
sbc_w      D0, G0      // summary  = k1 + k2*spt + sprt^3*k4/kp1 - k3*spt^2
..........................................
;   temper - kt
lds_w      E0, temper
ldi_w      E1, kt
sub_w      E0, E1
..........................................
;   (k1 + k2*spt + k4*spt^3/kp1  -  k3*spt^2 )*( temper - kt )
mov_d      dF, dC
muls_d_w            //  H0 : dG = dF * E0
..........................................
;   (k1 + k2*spt + k4*spt^3/kp1  -  k3*spt^2 )*( temper - kt ) /   kp2
ldi_d      dE, kp2
mov_d      dF, dG
mov_w      G0, H0
divs_wd_d            //   G0 : dF = G0 : dF  /  dE (sykned)
..........................................
;   S  -  (k1 + k2*spt + k4*spt^3/kp1  -  k3*spt^2 )*( temper - kt )  /   kp2
lds_w      E0, spt_curr
sub_w      E0, F0
sts_w      spt_20, E0   //  store result
ret
при принятой точности - выводим результат вычислений Sr на дисплей и отделяем запятой два знака справа макросом

Code
1
      itoa_16u            0,5,3   //(смещение в буфере),(кол-во выв цифр),(кол-во цифр целой части)
0 / 0 / 0
Регистрация: 26.01.2013
Сообщений: 208
22.12.2013, 15:18
Цитата Сообщение от wypuk
Так можно... НО!! Перед следующим умножением нужно отбросить 2 последних разряда, т.е разделить на 100! Как-то использовать операцию деления не хочется, т.к. она за долгие 7 тактов выполняется. А если делить сдвигом вправо, то разделить можно только на 64 или 128.
на заметку, деление через умножение
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 222
22.12.2013, 18:53
Ещё, до кучи
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
22.12.2013, 18:53
Помогаю со студенческими работами здесь

Умножение чисел с косвенной адресацией (ASM 51)
Приветствую! Нужна помощь, изучаю ассемблер и не могу разобраться как написать данную подпрограмму. Нужно перемножить двухбайтовые...

Умножение дробных чисел. КАК?
Собственно сабж: Подскажите примером, как в Label (=) получить 1200?

Как выполнить умножение на Atmega 8535 (ASM)?
Можно перемножить числа следующим образом? ldi r17 2 ldi r18 3 mul r18, r17 Куда будет заноситься результат?

Умножение двухбайтного на однобайтный прямой код (ATmega128, ASM)
Есть предмет телекоммуникации и то что нам читают на лекции ни как не связно с тем, что этот же преподаватель требует на лабах. Я его не...

Посчитать количество целых чисел, дробных чисел и десятичных чисел
Прошу помочь с заданием . Требуется посчитать количество целых, дробных и десятичных чисел в любой введеной строке. Пример строки...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Новые блоги и статьи
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизита табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать контроль заполнения реквизита "ПричинаСписания". . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
Программная установка даты и запрет ее изменения
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: при создании документов установить период списания автоматически. . .
Вывод данных в справочнике через динамический список
Maks 01.04.2026
Реализация из решения ниже выполнена на примере нетипового справочника "Спецтехника" разработанного в конфигурации КА2. Задача: вывести данные из ТЧ нетипового документа. . .
Программное заполнения текстового поля в реквизите формы документа
Maks 01.04.2026
Алгоритм из решения ниже реализован на нетиповом документе "ВыдачаОборудованияНаСпецтехнику" разработанного в конфигурации КА2, в дополнении к предыдущему решению. На форме документа создается. . .
К слову об оптимизации
kumehtar 01.04.2026
Вспоминаю начало 2000-х, университет, когда я писал на Delphi. Тогда среди программистов на форумах активно обсуждали аккуратную работу с памятью: нужно было следить за переменными, вовремя. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru