Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2005.06.06;
Скачать: [xml.tar.bz2];

Вниз

Алгоритм целочисленного деления или хотя бы деления на 10   Найти похожие ветки 

 
Defunct ©   (2005-05-17 06:37) [0]

Может есть что-нибудь быстрее дедовского метода (вычитание + сдвиг)?

PS: Проц умеет: складывать, вычитать и умножать (аппаратно!!) (ну и сдвигать, и стандартная логика and/or)


 
Иван Шихалев ©   (2005-05-17 07:10) [1]

Это что за проц такой, что делить не умеет?


 
Defunct ©   (2005-05-17 07:20) [2]

> Иван Шихалев

Atmel AVR


 
Kerk ©   (2005-05-17 07:34) [3]

Кнут. 2й том.


 
Antonn ©   (2005-05-17 07:58) [4]


> PS: Проц умеет: складывать, вычитать и умножать
> (аппаратно!!) (ну и сдвигать, и стандартная логика
> and/or)

проц умеет складывать, сравнивать и копировать. аппаратно.
вычитание - это сложение с обратным знаком. умножение - сложение с самим собой несколько раз.


 
Defunct ©   (2005-05-17 09:01) [5]

Kerk ©   (17.05.05 07:34) [3]

Нашел даже главу где написано про быстрое деление:
2 том. Глава 4.3.1. Алгоритм D (деление неотрицательных целых чисел)
но как назло нет у меня второго тома.. эх.

Antonn ©   (17.05.05 07:58) [4]
это к чему относится?


 
Иван Шихалев ©   (2005-05-17 09:07) [6]

http://www.atmel.ru/Articles/Atmel21.htm


 
Praco ©   (2005-05-17 09:33) [7]

Проц умеет только складывать


 
Jeer ©   (2005-05-17 09:44) [8]

Деление 8-и разрядных целых беззнаковых чисел (AVR)
;*** Использование регистров

.def drem8u=r15  ;остаток
.def dres8u=r16  ;результат
.def dd8u=r16  ;делимое
.def dv8u=r17  ;делитель
.def dcnt8u=r18  ;счетчик цикла
;*****
div8u_c sub drem8u,drem8u ;очистить остаток и перенос
ldi dcnt8u,9 ;инициализировать счетчик цикла
d8u_1:  rol dd8u ;делимое/результат сдвинуть влево
dec dcnt8u  ;уменьшить на единицу счетчик цикла
brne d8u_2  ;переход, если не ноль
ret   ;выход из подпрограммы
d8u_2:  rol drem8u ;остаток сдвинуть влево
sub drem8u,dv8u ;остаток= остаток - делитель
brcc d8u_3  ;если результат < 0
add drem8u,dv8u ;восстановить остаток
clc    ;сбросить перенос для  формирования результата
rjmp d8u_1  ;иначе
d8u_3:  sec  ;установить перенос для формирования результата
rjmp d8u_1  ;вернуться назад


 
Defunct ©   (2005-05-17 09:55) [9]

> Иван Шихалев

Спасибо большое, за то что прониклись моей проблемой, однако тот пример на сайте атмела работает в почти в два раза медленнее чем процедурка написанная мной (125 тактов против 77). И это при том, что у них не обрабатывается деление на 0 и плюс еще две ошибки в коде ;>

Я бы хотел как-то применить команду умножения для деления. мне бы именно алгоритм, а не код.

Большое спасибо всем кто откликнулся.
Kerk, тебе отдельное, 2-й том обязательно найду к вечеру ;>


 
Defunct ©   (2005-05-17 09:57) [10]

Praco ©   (17.05.05 09:33) [7]

В datasheet"е четко написано - hardware multiplier.


 
Praco ©   (2005-05-17 10:06) [11]

Defunct ©   (17.05.05 09:57) [10]
datasheet - что это?

В институте учили так:
Умножение - это многократное сложение, деление - многократное вычитание, вычитание - сложение с операндом, переведенным в дополнительный или обратный код, перевод в доп. код - примерно то же сложение.
Хотя может мои знания устарели?


 
Defunct ©   (2005-05-17 10:16) [12]

> datasheet - что это?
Достоверный документ от фирмы производителя на конкретное устройство.

> Хотя может мои знания устарели?
помните табличку умножения тетрадках сзади рисовали?
вот и в процессор можно встроить ПЗУшку-таблицу умножения и выполнять табличное умножение за 1 такт.


 
Anatoly Podgoretsky ©   (2005-05-17 10:41) [13]

Defunct ©   (17.05.05 10:16) [12]
Если будет желание потерять 128 кб, а так как стандартная ячейка памяти вроде 6 транзисторов, то можешь посчитать стоит ли овчинка выделки.


 
Alx2 ©   (2005-05-17 10:43) [14]

Приближение x/10 ~ 26*x/256=x/16+x/32+x/128 не поможет?
Относительная ошибка = 1/64  т.е. целая часть начинает "врать" для x>=640


 
TUser ©   (2005-05-17 10:46) [15]

Могу выслать эти разделы Кнута. Деление чисел с плавающей точкой - 6.5 М, целочисленное деление с применением длинной арифметики (алгоритм D) - 6.3 М.


 
Alx2 ©   (2005-05-17 10:50) [16]

Вдогонку Alx2 ©   (17.05.05 10:43)
Вот, нашел источник де жа вю :)
http://www.telesys.ru/wwwboards/mcontrol/51/messages/393.shtml


 
Jeer ©   (2005-05-17 11:20) [17]

Известен алгоритм деления на константу на основе умножения.
Для каждой константы свои MN и N
Приведено для asm i86
По аналогии можно перевести на asm AVR

mov eax,X
mov edx, MN
inc eax
mul edx
SHR edx, N

z = x/y
y = 123
MN = 2234779731
N = 6


 
Sha ©   (2005-05-17 11:54) [18]

> Defunct ©   (17.05.05 06:37)  
> PS: Проц умеет: ... умножать (аппаратно!!) (ну и сдвигать, и стандартная логика and/or)

Доп. вопросы:
1) какое деление интересует 8,16,32-бит ?
2) сколько бит имеет результат умножения 8х8,16х16,32х32 ?


 
Jeer ©   (2005-05-17 12:18) [19]

AVR  имеют аппаратный умножитель 8x8 (знаковое, безнаковое, целочисленный, дробный форматы) -> 16-битный результат за 2 такта.


 
Sha ©   (2005-05-17 12:42) [20]

Для реализации беззнакового деления на 10
надо реализовать следующие алгоритмы:

08 бит: j:=(i*$CD) shr 11;
16 бит: j:=(i*$CCCD) shr 19;
32 бит: j:=(i*$CCCCCCCD) shr 35;


 
Jeer ©   (2005-05-17 13:21) [21]

Добавление:
если требуется делить с округлением то

y:=(x*$CCCD) shr 18;
t := y and 1;
y := y shr 1;
if (t=1) then inc(y);


 
Antonn ©   (2005-05-17 13:28) [22]

Defunct ©   (17.05.05 9:01) [5]
это к чему относится?

к первому посту. Все операции (при рассмотрении на "аппаратном уровне") выполняются только тремя операциями [4].
Praco ©   (17.05.05 9:33) [7]
не только.


 
Sha ©   (2005-05-17 14:33) [23]

> Jeer ©   (17.05.05 13:21) [21]
> если требуется делить с округлением то ...

можно короче, например для 08 бит:

 k:=i*$CD;
 j:=k shr 11;
 if k and ($0400)<>0 then inc(j);


 
Jeer ©   (2005-05-17 17:06) [24]

Где мне спорить со знаменитым Шароховым :)


 
Defunct ©   (2005-05-17 20:49) [25]

Anatoly Podgoretsky ©   (17.05.05 10:41) [13]
Память ограничена.. 4kb еще можно было бы выделить, а 128k просто нет..

Alx2 ©   (17.05.05 10:43) [14]
хм.. попробую

TUser ©   (17.05.05 10:46) [15]
Буду очень благодарен!


Sha ©   (17.05.05 12:42) [20]
Спасибо, алгоритм - супер! Летает ;>


 
Defunct ©   (2005-05-17 23:33) [26]

Antonn ©   (17.05.05 13:28) [22]
> Все операции (при рассмотрении на "аппаратном уровне") выполняются только тремя операциями [4].

Если уйти глубоко в аппаратную реализацию, то абсолютно все операции можно выполнить на любом функционально полном наборе логики, например - И-НЕ.

А если все же применительно к процессорам, производитель может применять на аппаратном уровне какие-то свои схемные решения, которые выходят за предел перечисленных вами операций [4] (хотя бы вы забыли про незаменимую операцию сдвига, без нее ни туда и ни сюда). В данном случае AVR выполняет 130 команд аппаратно и имеет производительность (MIPS) приблизительно равную равную тактовой частоте.

Кстати, сравнивать умеют далеко не все процессоры, например:
- C51 не имеет команд сравнения двух чисел (аналога cmp), вместо нее есть команда вычитания, что фактически одно и то же;
- В PIC нет команд условного перехода.


 
_silver ©   (2005-05-18 00:15) [27]

А разве cmp не вычетает, а результат её влияет на флаги?


 
Defunct ©   (2005-05-18 01:01) [28]

cmp вычитает и не сохраняет рез-тат


 
Antonn ©   (2005-05-18 05:20) [29]

Defunct ©   (17.05.05 23:33) [26]
я, вообще то, просто поправил PS в первом посту, сдвиг можно выполнить копированием, вычитание и умножение выполняется посредством сложения. сравнение и есть and/or.


 
Defunct ©   (2005-05-18 06:51) [30]

Antonn ©   (18.05.05 05:20) [29]
Заблуждаетесь.

"ну помогай Вам Бох" (C) MSVspishkin и Никифоровна.


 
Sha ©   (2005-05-18 09:03) [31]

> Defunct ©   (17.05.05 20:49) [25]
> Летает ;>

Чтобы летало быстрее:

Часто кроме операции div 10
бывает необходима операция mod 10.
Например, для своей реализации IntToStr.

Mod 10 тоже можно выполнить при помощи умножения
и даже совместить обе операции и выполнить
их при помощи единственного умножения.

Пример на BASM для IA32 ниже.

function DivMod10_Sha(var Value: cardinal): cardinal; overload;
asm
 push eax
 mov  eax, [eax]
 mov  edx, $CCCCCCCD
 mov  ecx, eax
 mul  edx
 xor  ecx, edx
 mov  eax, edx
 and  ecx, 1
 and  eax, 7
 jnz  @nzero
 test ecx, ecx
 jz   @zero
@nzero:
 sub  eax, ecx
 add  eax, 2
@zero:
 pop  ecx
 shr  edx, 3
 mov  [ecx], edx
 end;


Примеры использования ниже.

function IntToStr_Sha(Value: integer): string;
var
 Buffer: array [0..11] of char;
 Negative, Blank: integer;
begin;
 Negative:=0;
 if Value<0 then begin;
   Negative:=-1;
   Value:=-Value;
   end;
 Blank:=High(Buffer);
 repeat;
   Buffer[Blank]:=char(ord("0")+DivMod10_Sha(cardinal(Value)));
   dec(Blank);
   until Value=0;
 Buffer[Blank]:="-";
 Blank:=Blank+Negative;
 SetString(Result,pchar(@Buffer[Blank+1]),High(Buffer)-Blank);
 end;

function IntToStr_Sha2(Value: integer): string;
var
 Pos: integer;
 Res: pchar;
begin;
 Pos:=0;
 if Value<0 then begin;
   Value:=-Value;
   Pos:=Pos+1;
   end;

 case Value of
   0..9: Pos:=Pos+1;
   10..99: Pos:=Pos+2;
   100..999: Pos:=Pos+3;
   1000..9999: Pos:=Pos+4;
   10000..99999: Pos:=Pos+5;
   100000..999999: Pos:=Pos+6;
   1000000..9999999: Pos:=Pos+7;
   10000000..99999999: Pos:=Pos+8;
   100000000..999999999: Pos:=Pos+9;
   else Pos:=Pos+10;
   end;

 SetLength(Result,Pos);
 Res:=pointer(Result);
 Res[0]:="-";
 repeat;
   Res[Pos-1]:=char(ord("0")+DivMod10_Sha(cardinal(Value)));
   dec(Pos);
   until Value=0;
 end;


Думаю, их можно адаптировать под твой суперпроцессор.
Можно это дело еще ускорить раза в 2, если на нем сложение
раз в 10-20 быстрее умножения или есть нечто похожее на LEA.


 
Defunct ©   (2005-05-18 20:39) [32]

Sha ©   (18.05.05 09:03) [31]
> Например, для своей реализации IntToStr.

Именно для нее и нужно было деление на 10. :)

> их при помощи единственного умножения.
Спасибо, но это уже оптимизация под x86, в AVR нахождение частного и остатка за 2 умножения (даже за 3) работает быстрее.
Еще раз большое спасибо за предложенный алгоритм!!
 
;-----------------------------------------------------
; Функция 8-ми разрядного целочисленного деления на 10
;---> BL - 8-ми разрязное делимое
;<--- BL - ОСТАТОК,  BH - ЧАСТНОЕ
div10_8:
  ldi  AL, $CD       ; ldi - аналог mov для загрузки констант
  mul  BL, AL        ; Результат умножения в DH:DL
  mov  BH, DH
  ldi  AL, 0b00010000; Для сдвига на 3
  fmul BH, AL        ; Дробное умножение на 0.001 (shr BH, 3)
  mov  BH, DH        ; <--- BH - Частное
  ldi  AL, 10        ;
  mul  BH, AL        
  sub  BL, DL        ; <--- BL - Остаток
  ret

;ps: названия регистров могут отличаться от реально используемых


> Mожно это дело еще ускорить раза в 2, если на нем сложение
> раз в 10-20 быстрее умножения или есть нечто похожее на LEA.
Сложение и умножение выполняются почти одинаково (1 и 2 такта соответственно).



Страницы: 1 вся ветка

Форум: "Потрепаться";
Текущий архив: 2005.06.06;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.014 c
14-1116494164
BJValentine
2005-05-19 13:16
2005.06.06
Описалово компонентов RxLib


1-1116778118
Starcom
2005-05-22 20:08
2005.06.06
Бегущая строка в StatusBar


1-1116477407
Andurbay
2005-05-19 08:36
2005.06.06
Печать в Delphi


1-1116718562
grol
2005-05-22 03:36
2005.06.06
Ввод чисел перед переменными в выражении в строке Edit.


1-1116923548
Phoenix
2005-05-24 12:32
2005.06.06
Субменю в PopupMenu





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский