Здорово. Подглядывая за сорсами фасма и до(пере)делывая программу конвертации чисел(без нее мне плохо в голове вертеть), заинтересовался делением через умножение и работой без FPU(фасм щитает без него). Подражание фасму удалось, заместить деление умножением тоже. Процедура <bsa_a2f> работает опционально в FPU-режиме, когда 10^x ищем за формулой; и без FPU, циклически умножая результат на 10 или на 0.1 соответственно. Но это медленно, хотелось тоже через формулу, используемую в <power10>. Постает вопрос: как получить 2^дробь. Рузультат, напомню, будет = (1;2). Тема эта мне, как и многим, будет полезна, поэтому ложу ссылки. Прошу ДАДАДА прощения, но тексты не русские. Также выложено программу-конвертер и сорс для заинтересовавшихся/нужденных. Исполнительный файл и тексты интерфейса: http://board.flatassembler.net/download.php?id=5106 Тексты вызываемых функций, там и float-процедуры: http://board.flatassembler.net/download.php?id=5043 Теория, как делить, умножая, и доп. тулза(web-script) от неизвестного мне автора http://board.flatassembler.net/topic.php?p=114917#114917 Теория на русском(не много), смотрите длинный комментарий поста #16: http://wasm.ru/forum/viewtopic.php?id=26577 aggro, туда(#16) постил в целях быстрого поиска жуков и только, ну и в целях примирения с форумом, видь я сука был. В обновленном файле доделаные лежат. Ну вот, приветствую, спасибо и добро пожаловать. 06:01, утро, мог напутать
Хороший сайт, в низу эмуляторы FPU: http://www.fdd5-25.net/emulators.php редактировал и прицепил файлик
Ссылка сюда лежит на другом форуме, e-mail'ах, потому комментировал одным языком. 10^простите, я НЕ специально. Ок, привет! Процедура еще не умеет подносить в отрицательную степень: мне нужно научиться делить. Прогортайте до .solve_result - там стоит "hlt". Как умны камни. Древние давно знали это.) Понимаю одного человека, который праду говорил, что все комментарии не влезут, и я школота. Хохохо, здоров був! Много не тестировал, мне трудно. Код (Text): mov eax,dword[f] mov ebx,dword[f+4] mov cx,word[f+8] call f2xm0 push ecx ebx eax fld tbyte[esp] add esp,12 ret f dt 0.51 ;f: dd $ffff'ffff,$ffff'ffff,$0000'3ffe ; IT MUST BE TESTED ; -1.0..+1.0 -> ecx:ebx:eax ; ecx:ebx:eax <- +0.5..+2.0 <- 2^ecx:ebx:eax <-no fpu ; flags.cf <- error proc f2xm0 ;before you start: make sure you know fpu-nums and understand the graph push edx ;modified regs here stc ;error=1 pushf shl ecx,1 ;blow-out sign bit... shr cx,1 ;...to operate easy jz .0? ;try returning 2^0=1 sub cx,$3fff je .1? ;try returning 2^-1=0.5 or 2^1=2 ja .nok ;value must be within -1.0..+1.0 test ebx,ebx jns .nok ;wrong format push ecx ;keep value's sign in bit 16; keep current exponent cmp cx,$ffff jne .x_less_0.5 ;method<0.5, remember the picture/graph, we are under 0.5 sub ebx,$8000'0000 ;method>=0.5, remember the picture jnz @f ;not 0.5 = const test eax,eax jz .1.4142135623730950480;0.5=const xchg ebx,eax ;partially normalize mov word[esp],-33 ;=-1-32, exponent updated @@: bsr ecx,ebx ;continue normalization process neg ecx add ecx,31 ;times to shift left sub [esp],cx ;keep exponent balance shld ebx,eax,cl shl eax,cl ;normalization finished ;$0000'3FFF=0 ;magic=1.1715728752538099310 mov edx,$95F6'1998 mov ecx,$0C43'3800 call .mul inc ecx ;compare with another "magic" pop edx ;restore old exponent add cx,dx ;multiplication finished: values multiplied & exponents summed neg cx ;1 and more=const cmp cx,63 jna @f ;near 0.0, so finish mode>=0.5 jmp .1.414213562373095048_ .1.4142135623730950480: pop edx .1.414213562373095048_: mov ecx,$0000'3FFF mov ebx,$B504'F333 mov eax,$F9DE'647D jmp .solve_result @@: shrd eax,ebx,cl ;getting real non-normalized result to sum it with 1.4142135623730950480 <- magic #3, remember the picture shr ebx,cl xor ecx,ecx add eax,$F9DE'647D ;magic #3 adc ebx,$B504'F333 ;remember the picture adc ecx,0 ;ecx<2=const shrd eax,ebx,cl shrd ebx,ecx,cl ;normalization finished add ecx,$0000'3fff ;valid float got jmp .solve_result .x_less_0.5: ;$0000'3FFE=-1 ;magic=0.8284271247461900689 mov edx,$D413'CCCF mov ecx,$E779'9000 call .mul ;x*magic, exponent adjusting comes then pop edx ;restore old exponent add cx,dx ;hint: when we multiply mantissas, exponents must be summed :) neg cx ;cx=2 and more=constant cmp cx,$003f ja .1 ;to get actual value, we must shift it right more than 63 times ie. adding 1.0 to it will bring 1.0 anyway as there are no so many bits defines by the floating standard cmp cx,$001f jna @f ;shift count < 32 mov eax,ebx xor ebx,ebx sub cl,$20 ;so many times left to shift right @@: shrd eax,ebx,cl shr ebx,cl bts ebx,31 ;add 1.0 :), so easy mov ecx,$0000'3fff ;1.xxx=const .solve_result: bt edx,16 jnc .ok ;x positive hlt .1?: cmp ebx,$8000'0000 jne .nok ;wrong format test eax,eax jnz .nok ;wrong format bt ecx,16 mov ecx,$0000'4000 jnc .ok ;2^1=2 mov ecx,$0000'3ffe jmp .ok ;2^-1=0.5 .0?: or ebx,eax jnz .nok ;wrong format mov ecx,$0000'3fff ;exponent=0 bts ebx,31 ;mantissa=1 jmp .ok ;2^0*1=1 .1: mov ecx,$0000'3fff ;exponent=0 mov ebx,$8000'0000 ;mantissa=1... xor eax,eax ;... -> 2^0*1=1 .ok: dec byte[esp] ;error=0 .nok: popf pop edx ret 0 ;hi Tomasz! .mul: call _64mul64 mov eax,ecx ;in both modes(before 0.5 and after) bit 128 may be zero - normalize bsr ecx,edx neg ecx add ecx,31 ;times to shift left shld edx,eax,cl shld eax,ebx,cl mov ebx,edx ;ebx:eax=valid float neg ecx ;to keep exponent balance ret 0 endp ;you may skip it though it's interesting ; $ffffffff(edx)ffffffff(ecx) * $ffffffff(ebx)ffffffff(eax) = ;=$ffffffff'ffffffff * $1'00000000'00000000 - $ffffffff'ffffffff = ;=$ffffffff'ffffffff'00000000'00000000 - $ffffffff'ffffffff = ;=$ffffffff'ffffffff'00000000'00000000 - 1 - $ffffffff'fffffffe = ;=$ffffffff'fffffffe'ffffffff'ffffffff - $ffffffff'fffffffe = ;=$ffffffff'fffffffe'00000000'00000001, 128 bits :b ;edx:ecx:ebx:eax = edx:ecx*ebx:eax = ecx*ebx:eax+(edx*ebx:eax)shl 32 ;flags = ? proc _64mul64 push eax ebx edx call _64mul32 xchg eax,[esp+8] xchg ebx,[esp+4] xchg ecx,[esp] call _64mul32 mov edx,ecx mov ecx,ebx mov ebx,eax pop eax add ecx,eax adc edx,0 pop eax add ebx,eax adc ecx,0 adc edx,0 pop eax ret 0 endp ;ecx:ebx:eax = ecx*ebx:eax = ecx*ebx:0+ecx*0:eax ;edx = ?, ecx*0:eax shr 32 actually ;flags = ? proc _64mul32 xchg eax,ebx mul ecx xchg ebx,eax xchg ecx,edx mul edx add ebx,edx adc ecx,0 ret 0 endp
Разбивая на больше частей, можно не делить там, где hlt. ... Лучьше циклить: f2xm1 не очень точный даже в исполнении железа. В наше время такой подход тупой, точный, иногда полезный, конец, спасибо. murder, в каком-то коде от тебя видел другую константу дл яделения на десятку, но та не всегда срабатывает, AMD тоже об том говорит. Надеюсь, с вами все ок, пропал куда-то. Код (Text): ;Умножить мантису TBYTE-float на 0.1 или 10 соответсвтенно. ;Процедура писалась под цикл, потому не проверяет, нормализировано ли число, иль не равно оно нулю. ;Делайте то сами лучьше раз и не посылайте проке таких чисел. ; мантиса -> ebx:eax ; ebx:eax <- нормализированный результат/мантиса ; ecx <- суммируйте с изначальной степенью числа для оплучения окончательного результата ; flags <- ? ;пример: mov esi,$0000'400e ; mov ebx,$ffff'0000 ; mov eax,$0000'0000 ; push esi ebx eax ; fld tbyte[esp] ; ; call fp_div ; add esi,ecx ; push esi ebx eax ; fld tbyte[esp] ; ; call fp_mul ; add esi,ecx ; push esi ebx eax ; fld tbyte[esp] ; ; add esp,12*3 proc fp_div push edx ;его меняем ;$0000'3ffb=-4 ;это и есть 0.1 mov edx,$cccc'cccc mov ecx,$cccc'cccd call _64mul64 ;sizeof.integer=1..2 бит, sizeof.fraction=126 бит mov eax,ecx bsr ecx,edx neg ecx add ecx,31 ;0..1 shld edx,eax,cl shld eax,ebx,cl ;float нормализировали mov ebx,edx ;результат готов pop edx neg ecx add ecx,-4+1 ;^умножая, степени суммируют^; +1 так как sizeof.integer=1..2, а в нормализированном числе sizeof.integer=1 ret 0 endp proc fp_mul push edx ;предохраняйтесь Ж) mov edx,$a0000000 ;10.0 = $4002'a0000000'00000000, пок. спенени два = 3: 1.010b xor ecx,ecx call _64mul64 ;то само mov eax,ecx bsr ecx,edx neg ecx add ecx,31 ;то само shld edx,eax,cl shld eax,ebx,cl mov ebx,edx pop edx neg ecx add ecx,3+1 ;+3 - вспомните 10.0; +1 - представьте, что ecx=-1 ret 0 ;ИЛИ: "для получения человеческого числа нужно кому переместить на 3 позиции вправо, если нормализация не проводилась - еще раз вправо" endp ;здорово Clerk, комментарии не влазят :)