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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Математический вопрос, Программирование на ассемблере
d7d1cd
сообщение Dec 21 2013, 16:41
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



Привет всем. Я программирую на ассемблере. В моей программе все числа хранятся в 32-х разрядах. Соответственно, математические операции (умножение, деление и прочие), реализованы с помощью функций, которые так же работают с 32-х разрядными числами.
Сейчас возникла такая проблема. Мне необходимо сделать вычисления по следующей формуле: X = A * B / C. Числа A, B, C, X - 32-х разрядные. Результат в Х точно поместится в 32 разряда, но при выполнении операции А*В может получится 64-х разрядное число. Подскажите, возможно ли, не прибегая к использованию 64-х разрядных функций и чисел, выполнить вычисления по формуле?

P.S. Функция деления возвращает 2 результата: частное и остаток. Все числа исключительно положительные.
Go to the top of the page
 
+Quote Post
Xenia
сообщение Dec 21 2013, 16:55
Сообщение #2


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(d7d1cd @ Dec 21 2013, 20:41) *
... но при выполнении операции А*В может получится 64-х разрядное число. Подскажите, возможно ли, не прибегая к использованию 64-х разрядных функций и чисел, выполнить вычисления по формуле?


Откуда такое ограничение? Чем, собственно, плохо 64-разрядное число в качестве промежуточного результата?
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Dec 21 2013, 17:11
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



Цитата(Xenia @ Dec 21 2013, 20:55) *
Откуда такое ограничение? Чем, собственно, плохо 64-разрядное число в качестве промежуточного результата?

Для этого надо писать функцию умножения с получением 64-х разрядного результата, а так же функцию деления 64-х разрядного числа. Я не случайно пишу на асме: у меня места под мою программу очень мало и лишние функции это не айс. Если бы в моем распоряжении была вся память, то я бы писал на С и не задавал таких вопросов.
Go to the top of the page
 
+Quote Post
lekintr
сообщение Dec 21 2013, 17:15
Сообщение #4


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

Группа: Участник
Сообщений: 112
Регистрация: 10-10-13
Пользователь №: 78 684



Цитата(d7d1cd @ Dec 21 2013, 20:41) *
Результат в Х точно поместится в 32 разряда, но при выполнении операции А*В может получится 64-х разрядное число.
P.S. Функция деления возвращает 2 результата: частное и остаток. Все числа исключительно положительные.


Если два числа умноженные друг на друга дают 32 разрядное число, значит сами эти числа можно уместить в 16 разрядов. Ну так преобразуйте множители в 16 разрядов и умножайте хоть до посинения...

Сообщение отредактировал lekintr - Dec 21 2013, 17:15
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Dec 21 2013, 17:37
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



Ну вообще то под словами "результат в Х" понимается результат от А*В/С. Два числа (А и В), умноженные друг на друга, как раз могут и не поместиться в 32 разряда.
Go to the top of the page
 
+Quote Post
kovigor
сообщение Dec 21 2013, 19:20
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(d7d1cd @ Dec 21 2013, 20:37) *
Ну вообще то под словами "результат в Х" понимается результат от А*В/С. Два числа (А и В), умноженные друг на друга, как раз могут и не поместиться в 32 разряда.

А что мешает "A" разделить на "C" и полученный результат умножить на "B" ?

И вообще, если вы не делаете достаточно крупную серию, возьмите более подходящий МК и пишите на Си. Есть, конечно, исключения, но в общем случае выбор для проекта такого МК, который подходит "впритык", есть признак дурного тона. А если завтра потребуется простейшая модернизация ПО, что вы станете делать ?
Go to the top of the page
 
+Quote Post
Егоров
сообщение Dec 21 2013, 21:53
Сообщение #7


Гуру
******

Группа: Модераторы
Сообщений: 3 868
Регистрация: 15-03-13
Пользователь №: 76 048



Хм.. так 32 разряда - точность. Умножайте спокойно и 32 младших разряда отбрасывайте.
Иначе, при 64-разрядном процессоре Вы тоже встанете в тупик - куда девать результат в 128 разрядов? И так без конца.
На 8-битных процессорах почему-то таких проблем не возникало раньше. Считали с любой требуемой точностью.
Как мы в столбик считаем до 1% или 0.1% ? Младшие разряды отбрасываем, или округляем.
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Dec 22 2013, 06:26
Сообщение #8


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



Цитата(kovigor @ Dec 21 2013, 23:20) *
А что мешает "A" разделить на "C" и полученный результат умножить на "B" ?

Ничего не мешает. Разве только потеря точности. Ведь деление то целочисленное. Или как то можно остаток использовать?

Цитата(kovigor @ Dec 21 2013, 23:20) *
И вообще, если вы не делаете достаточно крупную серию, возьмите более подходящий МК и пишите на Си. Есть, конечно, исключения, но в общем случае выбор для проекта такого МК, который подходит "впритык", есть признак дурного тона. А если завтра потребуется простейшая модернизация ПО, что вы станете делать ?

К великому моему сожалению заменить МК нельзя. А места в нем мало от того, что в нем уже есть программа, а я хочу добавить туда свой код. В общем есть задача, описанная в начале. Надо ее решить...

Цитата(Егоров @ Dec 22 2013, 01:53) *
Хм.. так 32 разряда - точность. Умножайте спокойно и 32 младших разряда отбрасывайте.
Иначе, при 64-разрядном процессоре Вы тоже встанете в тупик - куда девать результат в 128 разрядов? И так без конца.
На 8-битных процессорах почему-то таких проблем не возникало раньше. Считали с любой требуемой точностью.
Как мы в столбик считаем до 1% или 0.1% ? Младшие разряды отбрасываем, или округляем.

Представьте такую ситуацию в моей программе: A=0x3B8B87C0, B=0x34EDCE00, C=0x2E501440. Если выполнить целочисленную арифметику по моей формуле (с использованием любого количества разрядов), то результат будет: X = 0x440D2D6D. Такой результат должна выдавать моя программа.
Теперь по Вашему совету:
1. A*B = 0x3B8B87C0 * 0x34EDCE00 = 0xC4FA7A9F3FC8000
2. Отбрасываем младшие 32 разряда: 0xC4FA7A9F
3. Выполняем деление: 0xC4FA7A9F / 0x2E501440 = 0х00000004
4. Как я понимаю, возвращаем "утраченные" разряды: 0х40000000

Видно, что 0x440D2D6D и 0х40000000 даже приблизительно не равны. Или я чего не правильно сделал???
Go to the top of the page
 
+Quote Post
PRidon
сообщение Dec 23 2013, 07:38
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 29
Регистрация: 8-10-12
Пользователь №: 73 855



Ну есть один вариант. Делал похожее умножение на 8ми битке.
Пусть XY и AB - исходные числа. (каждая буква - 16 бит)
XY*AB= CDEF
где CD = X*A + 'старшие 16 бит'(A*Y+B*X),
EF = 'младшие 16 бит'(A*Y+B*X) + Y*B,
т.е. получаем 2 числа по 32 бита. Причем получаем оперируя только 32х битными числами.
Деление выполняется так же.
Единственный минус: на 3 больше умножений и на 2 больше делений. Ну а если уже написанная функция возвращает и остаток, и результат деления, то проблем быть не должно.
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Dec 23 2013, 17:34
Сообщение #10


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



Цитата(PRidon @ Dec 23 2013, 11:38) *
Ну есть один вариант. Делал похожее умножение на 8ми битке.
Пусть XY и AB - исходные числа. (каждая буква - 16 бит)
XY*AB= CDEF
где CD = X*A + 'старшие 16 бит'(A*Y+B*X),
EF = 'младшие 16 бит'(A*Y+B*X) + Y*B,
т.е. получаем 2 числа по 32 бита. Причем получаем оперируя только 32х битными числами.
Деление выполняется так же.
Единственный минус: на 3 больше умножений и на 2 больше делений. Ну а если уже написанная функция возвращает и остаток, и результат деления, то проблем быть не должно.

Спасибо за совет. Вот сейчас именно то, что надо. Но я тоже долго размышлял над задачей и подумал, что мне лучше переписать функции умножения и деления. То есть, функция деления должна делить 64-х битное число на 32-х битное и возвращать 32-х битное, а функция умножения должна перемножать 32-х битные числа и возвращать 64-х битное.
Функцию деления, я думаю, переписать смогу, а вот с функцией умножения загвоздка. Я хочу применить аппаратный умножитель, но не совсем разбираюсь в его регистрах. Функция умножения 32-х битных чисел и возвращения 32-х битного результата выглядит так:
Код
mov.w   R12,&MPY
mov.w   R14,&OP2
mov.w   R12,&MAC
mov.w   &RESLO,R12
mov.w   &RESHI,&RESLO
mov.w   R15,&OP2
mov.w   R13,&MAC
mov.w   R14,&OP2
mov.w   &RESLO,R13

В этой функции R12 и R13 - это первый множитель (R12 - младшее слово), R14 и R15 - второй множитель (R14 младшее слово). Результат я получаю в регистрах R12 и R13 (R12 - младшее слово). Подскажите, как мне получить 64-х битный результат умножения (в регистрах R12-R15)?
Go to the top of the page
 
+Quote Post
PRidon
сообщение Dec 24 2013, 06:18
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 29
Регистрация: 8-10-12
Пользователь №: 73 855



Процессор та какой?
Если умножитель аппаратный, то либо 16х16=32, либо 32х32=64. А 32х32=32 - смысла особого не имеет.

Код
mov.w   R15,&MPY;загружаем 1е операнды (15х13)
mov.w   R13,&OP2
; 3 такта ждать
mov.w   &RESHI,R15; результат
mov.w   &RESLO,&RESHI
mov.w   &MPY ,&MAC;загружаем 2е операнды с суммированием результата (15х12) Если такая форма сработает - все получится. Если нет, готовь еще 4 регистра.
mov.w   R12,&OP2
; 3 такта ждать
add.w    &SUMEXT,R15; учитываем переполнение
mov.w   R14,&MAC;загружаем 3е операнды с суммированием результата (14х13)
mov.w   R13,&OP2
; 3 такта ждать
add.w    &SUMEXT,R15; учитываем переполнение
mov.w   &RESHI,R14   ; записываем результат
mov.w   &RESLO,&RESHI
mov.w   R12,&OP2      ; загружаем 4е операнды с суммированием результата (14х12)
; 3 такта ждать
add.w    &SUMEXT,R14; учитываем переполнение
; тут надо проверить переполнение через SR. И если флаг стоит - inc R15
mov.w   &RESHI,R13  ; опять же результат
mov.w   &RESLO,R12  ; и последний результат

Проверить возможности нет. Но мысля что будет работать.
Сработает если после чтения регистров RESLO и RESHI они обнуляются, в UG про это ничего не написано. Так же не очень понятно по какому принципу будет определяться 1й операнд. Если по последней записи, то должно работать.
зы: и да, на умножение нужно 3 такта. Не стоит забывать про это, особенно на асе.
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Dec 24 2013, 14:28
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



Цитата(PRidon @ Dec 23 2013, 11:38) *
Пусть XY и AB - исходные числа. (каждая буква - 16 бит)
XY*AB= CDEF
где CD = X*A + 'старшие 16 бит'(A*Y+B*X),
EF = 'младшие 16 бит'(A*Y+B*X) + Y*B,
т.е. получаем 2 числа по 32 бита. Причем получаем оперируя только 32х битными числами.

Кстати тут есть вопрос. Если выполнить A*Y+B*X, когда А=B=Y=X=0xFFFF, то получится 0х1FFFC0002, то есть число размером большее, чем 32 бита. Уже оперируем не 32-х битными значениями. Как из этого значения получить 'младшие 16 бит' понятно - это 0002. А как из этого числа получить 'старшие 16 бит' непонятно. По всей логике - это 0001. Что скажите?
Go to the top of the page
 
+Quote Post
PRidon
сообщение Dec 25 2013, 04:57
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 29
Регистрация: 8-10-12
Пользователь №: 73 855



Это обычное умножение столбиком. Что переполняется - увеличение старших разрядов. В приведенном мной коде это тоже учитывается. В частности в MSP430 есть статусный регистр, а в нем флаг переполнения. Да и в HM есть свой похожий регистр - SUMEXT, который я и использую.
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Dec 25 2013, 17:40
Сообщение #14


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



Итак, умножению иною реализовано. Вот код:
Код
//***** БЕЗЗНАКОВОЕ УМНОЖЕНИЕ 32-Х РАЗРЯДНОГО ЧИСЛА НА 32-Х РАЗРЯДНОЕ С ПОЛУЧЕНИЕМ 64-Х РАЗРЯДНОГО РЕЗУЛЬТАТА
;       R12, R13 - первый множитель. R12 - младшее слово
;       R14, R15 - второй множитель. R14 - младшее слово
Mul32u32uTo64u:                            
        MOV     R12, &MPY
        MOV     R14, &OP2
        MOV     R12, &MAC
        MOV     &RESLO, R12
        MOV     &RESHI, &RESLO
        CLR     &RESHI
        MOV     R15, &OP2
        MOV     R13, &MAC
        MOV     R14, &OP2
        MOV     R13, &MAC
        MOV     &RESLO, R13
        MOV     &RESHI, &RESLO
        MOV     &SUMEXT, &RESHI
        MOV     R15, &OP2
        MOV     &RESLO, R14
        MOV     &RESHI, R15
        RET
;       R12, R13, R14, R15 - произведение. R12 - младшее слово

Я думал, что с делением проблем не будет. Но оказалось, что будет... Сейчас думаю. Вопросов пока задавать не буду...
Go to the top of the page
 
+Quote Post
PRidon
сообщение Dec 26 2013, 05:31
Сообщение #15


Участник
*

Группа: Участник
Сообщений: 29
Регистрация: 8-10-12
Пользователь №: 73 855



как разберешься с делением - выложи результат. Полезная вещь.
Go to the top of the page
 
+Quote Post

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

 


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


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