Непонятно, что общего у этого кода с Montgomery. Монтгомери нужно полтора MUL для редукции, а здесь примерно то же что и у Майкла____. Еще нужен мультипликативный обратный с FFF00001, но приведенная константа на него не похожа. Так и не понятно, что делать при переполнении при сложении. Вычитать трансформированный p ? Вот код #27 как раз использует специфику чисел, близких к FFFFFFFF. С обычным простым от балды работать не будет. Классно работает у меня еще с FFFFFFFB, умножая на 5
А монтгомери полной редукции не гарантирует, он тока гарантирует отсутствие потери информации при переполнении, что частичный остаток влезет в 32-бит. Так что тут тоже нужен гимор с доводкой числа.
Предпоследний вариант кода из #81, до избавления от mul, принцип работы в точности такой же: Код (Text): start: mov ebp, 0xFFF00001 mov eax, 0x12345678 call input2coded mov ebx, eax mov eax, 0x9ABCDEF0 call input2coded mov edx, ebx call coded_mul call coded2output ; eax = residue ret coded2output: ; eax -> eax xor edx, edx jmp coded_mul_doit input2coded: ; eax -> eax mov edx, 0x0FDFFF01 coded_mul: ; eax*edx -> eax mul edx coded_mul_doit: imul eax, 0x100001 ; = -0xFFEFFFFF mov edi, edx mul ebp sub edi, edx sbb eax, eax and eax, ebp add eax, edi ret Мультипликативный обратный здесь равен 0xFFEFFFFF, он же -0x100001, что прекрасно описывается сдвигами. Этот код, как и предыдущий, а) полностью рабочий (можно проверять, заменяя 0x12345678 и 0x9ABCDEF0 на что-то своё) и б) следует методу Монтгомери. Тупой работающий вариант: Код (Text): coded_add: ; eax + edx -> eax add eax, edx jc overflow cmp eax, 0xFFF00001 jae overflow ret overflow: sub eax, 0xFFF00001 ret Тупость заключается в лишних ветвлениях, для большей скорости их нужно устранить.
Ну оптимальное сложение по модулю выглядит совсем по другому. Но вопрос не в этом. Я тоже сначала юзал заглушку на jc. Вопрос, если числа трансформированы, то как складывать? Чистый p выглядит подозрительным
за Монтгомери конечно спасибо, будем изучать... Еще бы разобраться со сложением трансформированных величин... Но впечатления двойственные, поскоку модуль специального вида, очевидно что и без монтгомери все можно сделать
Точно так же, как если они не трансформированы. Нужно просто вычитать p, если результат (с учётом возможного 32-битного переполнения) оказался больше или равен p. Ага, код из #78 это использует (потому что в коде из #83 можно заметить команду mul ebp, а в ebp хранится p).
хм.. столкнулся с мелкой проблемой относительно деления на пять. подсмотрев трюк у gcc.. Код (Text): unsigned short int xz (unsigned int my) { return my / 5; } .globl _xz .def _xz; .scl 2; .type 32; .endef _xz: mov edx, -858993459 mul edx shr edx, 2 mov eax, edx ret скопипастил сие решение, но решил оптимизнуть под свой код. в процесе чего были навешаны некоторые баги, и в результате что то я не понял.. почему работает как надо?? (а то код выполняется в критическом режиме...) Код (Text): program xz; var hook: function:integer; procedure IDTHook; forward; procedure _rise; asm sub [esp], offset IdtHook+5; mov eax, $CCCCCCCD // собственно тут mul eax, [esp] // деление add esp,4 end; procedure IDTHook; begin // ряд из 5-ти байтовых CALL-ов _rise(*00*); // Divide Error _rise(*01*); // Debug Exception _rise(*02*); // NMI Interrupt _rise(*03*); // Breakpoint _rise(*04*); // INTO-detected Overflow _rise(*05*); // BOUND Range Exceeded _rise(*06*); // Invalid Opcode _rise(*07*); // Device Not Available _rise(*08*); // Double Fault // и т.д end; begin hook := pointer(integer(@IdtHook)+$7 * 5); writeln (hook() ); end.
murder сенькс, крутая прожка.. вроде разобрался, в моем случае числа только кратные 5, и за чего оказалось возможным избавиться от xxx SHR 2 (пустячок, а приятно...)
капут Код (Text): ; ecx:ebx:eax <- 1/eax ; flags <- ? ; rus: Почему так: www.code.google.com\p\fasmme\ -> 80 bit floats. ; Внимательно прочитав инфу по ссылке выше, вы поймете, что весь трюк заключается в преобразовании числа 1 в двоичной системе счисления - в с основанием eax. ; Если вы полны извращенства, "1/eax" - не лимит этой процедуры, т.к. вместо 1... ; enu: Theory: www.code.google.com\p\fasmme\ -> 80 bit floats ; As you can see, the trick is based on binary 1 into eax'ary count system encoding. ; "1/eax" can be replaced with "2/eax" etc. ;format pe gui 4.0 ;include 'win32ax.inc' ; ;section '' code executable import readable writable ; library kernel32,'kernel32.dll',\ ; user32,'user32.dll' ; ; include 'api\kernel32.inc' ; include 'api\user32.inc' ; ; buf0 db 'dec: 0.' ; buf1 rb 32;*3 * log(10;2) ; db 10,'bin: 0.' ; buf2 rb 32*3 ; db 10,'hex: 0.' ; buf3 rb 32*3/4 ; db 0 ; ; entry $ ; mov eax,10;$ffff'ffff ; call reciprocal_dword ; ;dec ; push ecx ebx eax ecx ebx eax ecx ebx eax ; mov ecx,32 ; mov edi,buf1 ; @@:mov eax,10 ; mul dword[esp+8] ; mov [esp+8],eax ; lea ebx,[edx+'0'] ; mov eax,10 ; mul dword[esp+4] ; mov [esp+4],eax ; add [esp+8],edx ; adc ebx,0 ; mov eax,10 ; mul dword[esp] ; add [esp+4],edx ; adc dword[esp+8],0 ; adc ebx,0 ; mov al,bl ; stosb ; loop @b ; add esp,12 ; ;bin ; mov ecx,32*3 ; mov edi,buf2 ; pop ebx edx esi ; @@:shl ebx,1 ; rcl edx,1 ; rcl esi,1 ; mov al,0 ; adc al,'0' ; stosb ; loop @b ; ;hex ; mov ecx,32*3/4 ; mov edi,buf3 ; pop ebx edx esi ; @@:shld eax,esi,4 ; shld esi,edx,4 ; shld edx,ebx,4 ; shl ebx,4 ; and al,$0f ; add al,'0' ; daa ; cmp al,$0a+'0'+$06 ; sbb al,-1 ; stosb ; loop @b ; ; ; invoke MessageBoxA,0,buf0,'reciprocal_dword',0 ; ; invoke ExitProcess,0 proc reciprocal_dword xor ebx,ebx push ebx ebx ebx lea ecx,[ebx+32*3] inc ebx .to_bin:shl ebx,1 jc .put_ cmp eax,ebx ja .put .put_:sub ebx,eax stc .put: rcl dword[esp],1 rcl dword[esp+4],1 rcl dword[esp+8],1 loop .to_bin pop eax ebx ecx ret 0 ; 2010_11_28 endp
Код (Text): ; edx:ecx:ebx:eax <- 1/ebx:eax ; flags <- ? ;format pe gui 4.0 ;include 'win32ax.inc' ; ;section '' code executable import readable writable ; library kernel32,'kernel32.dll',\ ; user32,'user32.dll' ; ; include 'api\kernel32.inc' ; include 'api\user32.inc' ; ; buf0 db 'bin: ' ; buf1 rb 32*4 ; db 0 ; ; entry $ ; mov ebx,0;$ffff'ffff ; mov eax,3;$ffff'ffff ; call reciprocal_qword ; ;bin ; push edx ecx ebx eax ; mov ecx,32*4 ; mov edi,buf1 ; @@:shl dword[esp],1 ; rcl dword[esp+4],1 ; rcl dword[esp+8],1 ; rcl dword[esp+12],1 ; mov al,0 ; adc al,'0' ; stosb ; loop @b ; add esp,12 ; ; ; invoke MessageBoxA,0,buf0,'reciprocal_qword',0 ; ; ; invoke ExitProcess,0 proc reciprocal_qword push edi xor edi,edi push edi edi edi edi lea edx,[edi+1] lea ecx,[edx+32*4-1] ; < lea ecx,[edi+32*4] .to_bin:shl edx,1 rcl edi,1 jc .put_ cmp ebx,edi jb .put_ ja .put cmp eax,edx ja .put .put_:sub edx,eax sbb edi,ebx stc .put: rcl dword[esp],1 rcl dword[esp+4],1 rcl dword[esp+8],1 rcl dword[esp+12],1 loop .to_bin pop eax ebx ecx edx pop edi ret 0 ; 2010_11_28 endp
Воплотилось два поста выше: http://code.google.com/p/fasmme/downloads/detail?name=radix.rar&can=2&q= Так оно смотрится:
Один деятель уже писал в projects свой конвертор. Тот же глюк - где выделение периода дробной части у периодичесиких дробей?
Цветом? Поясни. То сами числа такие, так и должно быть. Проверял calc.exe, результат ок даже для сомнительного 1/MAXDWORD, когда в EBX:EAX=1(вызов reciprocal_dword). Казалось, чего может весить 2^-64: calc.exe: 2,3283064370807973754314699618685e-10 radix.exe: 0.000000000232830643708079 В самом первом посту спрашивается про замену деления умножением. Вот свойсно и оно. Чисто в практических целях. Трошка дописалось - подсвечивает число сдвигов(замена div). Моим мотивом было поделиться. По теме буду писать курсовую(нам можно за желанием). persicum, вы злы?
edemko : 5/6 = 0,8(3) 6/7 = 0,(857142) Кстати, мой calc.exe выдаёт иной результат для 2^(-64) = 5,4210108624275221700372640043497e-20 (Windows 7).
Результат возвращался в ECX:EBX:EAX=2^-32 + 2^-64, записанный как ненормализированное число = двоичная дробь наподобе десятичной. KeSqueer, Cпасибо за поправку. >не отвечать>Простите за наезд стосовно мягких(ь) знаков когда-то. dec: 0.000000000232830643708079 bin: 0.0000000000000000000000000000000100000000000000000000000000000001 hex: 0.0000000100000001 shl: 31 persicum, и что с этим делать?
Например, можно узнать, представимо ли число в двоичном виде (в сопроцессоре) точно или округленно? Например, 0.1? Ну и вообще, если конвертор посягает на числа с отрицательными позиционными знаками (т.е. с дробными частями), то пусть выделяет период. Сама по себе задача интересная, т.к. может быть подход к периоду, и только после этого начаться сам период.