ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Четверг
21 ноября
1069203 Топик полностью
Связанные сообщения
__Udivdi3Division
Никак? Обычно такие функции, которые не может выполнить аппаратура, реализуются в libgcc (см. по ссылке). Но в EABI (application...2020-09-05
I need to print signed 64-bit numbers in decimal form. Program runs in freestanding environment (no C library available, libgcc ...2018-09-06
fk0, легенда (14.01.2021 23:39, просмотров: 568) ответил FDA на Возникла проблема с 32-битной арифметикой. Компилятор XC8 для PIC18. Контроллер подключён к импульсному выходу электросчётчика. Количество импульсов на киловатт-час задаётся программно. Допустим это 3200 имп/кВт*ч. Счётчик 32-битный. Требуется выдавать "наружу" уже пересчитанное значение с точностью до Вт*ч. И тут появляется проблема. Я не могу сделать так: (cnt * 1000) / coeff, потому что при достижении значения в 4 млн. с чем-то импульсов у меня при умножении будет
1) посчитать с плавающей точкой... 2) написать 64-битную арифметику самостоятельно (это сделано в C-библиотеках многих процессоров на самом-то деле -- подсмотреть можно в libgcc), 3) взять библиотеку вроде BigNum (в RSA для pic18 такая какая-то и использовалась!) и посчитать с неограниченной разрядностью. По пункту 2 на самом деле проблема с делением. Лучше извернуть до cnt*other_coeff >> N. А уж умножить совсем не проблема, условно-поразрядно: 

a * b = (ahi*K + alo)*(bhi*K + blo) = ahi*bhi*K2 + (alo*bhi + ahi*bhi)*K + alo*blo

Где K2 -- это сдвиг влево на 64, а K -- сдвиг влево на 32 разряда.


Как сказано выше, задача может быть сведена к произведению и откидыванию младших разрядов.

Где множитель other_coeff = (k*1000 + coeff - 1) / coeff (где k = 2n). Часть "+coeff-1" нужна для округления.

Но работать это будет только для коэффициентов, условно, известных в момент компиляции. Для произвольных придётся делить на контроллере. Если множество коэффициентов фиксированное -- вариант. Если коэффициенты произвольные, то придётся осваивать один из алгоритмов деления...


Поделить можно в столбик, поразрядно, как в школе учили. Только в двоичной форме. В принципе алгоритм легко пишется на ассемблере... Например вот ссылка: http://bearcave.com/software/divide.htm

(приложил к сообщению, на случай отключения от интернета: divide.c


Описание алгоритмов деления используемых в библиотеке GMP:

https://gmplib.org/manual/Division-Algorithms#Division-Algorithms


Алгоритм деления на константу через умножение на обратную величину (то, что используется современными компиляторами, не уверен, впрочем, что к последним относится picc18...):

divcnst-pldi94_1_.pdf


В алгоритме суть, как использовать меньшее число разрядов-регистров. По-простому если, см. формулу выше.


Ссылки по теме (о 64-битном делении в C-бибиотеке):

http://caxapa.ru/1033958


Из ссылок по последней ссылке можно выдрать готовый код.

[ZX]