|
Математический вопрос, Программирование на ассемблере |
|
|
|
Dec 21 2013, 16:41
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Привет всем. Я программирую на ассемблере. В моей программе все числа хранятся в 32-х разрядах. Соответственно, математические операции (умножение, деление и прочие), реализованы с помощью функций, которые так же работают с 32-х разрядными числами. Сейчас возникла такая проблема. Мне необходимо сделать вычисления по следующей формуле: X = A * B / C. Числа A, B, C, X - 32-х разрядные. Результат в Х точно поместится в 32 разряда, но при выполнении операции А*В может получится 64-х разрядное число. Подскажите, возможно ли, не прибегая к использованию 64-х разрядных функций и чисел, выполнить вычисления по формуле?
P.S. Функция деления возвращает 2 результата: частное и остаток. Все числа исключительно положительные.
|
|
|
|
|
Dec 21 2013, 17:11
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(Xenia @ Dec 21 2013, 20:55)  Откуда такое ограничение? Чем, собственно, плохо 64-разрядное число в качестве промежуточного результата? Для этого надо писать функцию умножения с получением 64-х разрядного результата, а так же функцию деления 64-х разрядного числа. Я не случайно пишу на асме: у меня места под мою программу очень мало и лишние функции это не айс. Если бы в моем распоряжении была вся память, то я бы писал на С и не задавал таких вопросов.
|
|
|
|
|
Dec 21 2013, 17:15
|
Частый гость
 
Группа: Участник
Сообщений: 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
|
|
|
|
|
Dec 21 2013, 19:20
|
Гуру
     
Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295

|
Цитата(d7d1cd @ Dec 21 2013, 20:37)  Ну вообще то под словами "результат в Х" понимается результат от А*В/С. Два числа (А и В), умноженные друг на друга, как раз могут и не поместиться в 32 разряда. А что мешает "A" разделить на "C" и полученный результат умножить на "B" ? И вообще, если вы не делаете достаточно крупную серию, возьмите более подходящий МК и пишите на Си. Есть, конечно, исключения, но в общем случае выбор для проекта такого МК, который подходит "впритык", есть признак дурного тона. А если завтра потребуется простейшая модернизация ПО, что вы станете делать ?
|
|
|
|
|
Dec 22 2013, 06:26
|
Местный
  
Группа: Участник
Сообщений: 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 даже приблизительно не равны. Или я чего не правильно сделал???
|
|
|
|
|
Dec 23 2013, 07:38
|
Участник

Группа: Участник
Сообщений: 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 больше делений. Ну а если уже написанная функция возвращает и остаток, и результат деления, то проблем быть не должно.
|
|
|
|
|
Dec 23 2013, 17:34
|
Местный
  
Группа: Участник
Сообщений: 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)?
|
|
|
|
|
Dec 24 2013, 06:18
|
Участник

Группа: Участник
Сообщений: 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 такта. Не стоит забывать про это, особенно на асе.
|
|
|
|
|
Dec 24 2013, 14:28
|
Местный
  
Группа: Участник
Сообщений: 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. Что скажите?
|
|
|
|
|
Dec 25 2013, 04:57
|
Участник

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

|
Это обычное умножение столбиком. Что переполняется - увеличение старших разрядов. В приведенном мной коде это тоже учитывается. В частности в MSP430 есть статусный регистр, а в нем флаг переполнения. Да и в HM есть свой похожий регистр - SUMEXT, который я и использую.
|
|
|
|
|
Dec 25 2013, 17:40
|
Местный
  
Группа: Участник
Сообщений: 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 - младшее слово Я думал, что с делением проблем не будет. Но оказалось, что будет... Сейчас думаю. Вопросов пока задавать не буду...
|
|
|
|
|
Dec 26 2013, 05:31
|
Участник

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

|
как разберешься с делением - выложи результат. Полезная вещь.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|