ieee числа (c) maximum/integer
здравствуйте, дорогие читатели adventurer 'a, это вас снова тревожит maximum со своей неутолимой жаждой чтото писать в ассемблере...
на этот раз я представляю на ваш суд достаточно сложные процедурки, хотя для кого как... речь в данной статье пойдет о повальной метематике, всяких там косинусах и корнях, перемноженных на синус !
ну ладно, к телу, т. е. к делу:
многих, наверное, не устраивает скорость работы встроенного калькулятора, а с числами надо как-то работать, многие пишут умные процедурки, типа деления h на l, а на выходе в d целая часть, в e дробная часть числа, синус вычисляют по таблицам и т. д. и т. п.
здесь приводятся процедуры из библиотеки версии 1. 0, в нее вошли:
- сложение;
- вычитание;
- умножение;
- деление;
- косинус;
- синус;
- несколько вспомогательных процедур.
и все эти операции оперируют с ieee числами (вещественными), диапазон которых от -5. 9е-39 до +3. 4е38, обрабатывается 7 цифр после точки, что весьма точно ! для представления таких чисел нужно всего 4 байта, в форме мантисса-порядок. для операций над ieee числами используются регистры de и hl, d - для хранения порядка, ehl - для хранения мантиссы, 7 бит регистра h - хранит знак числа. например:
+--+--------+--------+--------+--------+ | | h | l | e | d | +--+--------+--------+--------+--------| |2=|01000000|00000000|00000000|00000001| | =|#40 |#00 |#00 |#01 | +--+--------+--------+--------+--------| |1=|01000000|00000000|00000000|00000000| | =|#40 |#00 |#00 |#00 | +--+--------+--------+--------+--------| |-12.5 | | | | | =|11100100|00000000|00000000|00000011| | =|#e4 |#00 |#00 |#03 | +--+--------+--------+--------+--------| |0.1 | | | | | =|01100110|01100110|01100110|11111100| | =|#66 |#66 |#66 |#fc | +--+--------+--------+--------+--------+
для облегчения работы с ieee были написаны две вспомогательные процедуры для перевода чисел из одной системы счисления в другую, т. е. из ieee в int, и наоборот (int - это слово со знаком).
в данных процедурах могут возникать математические ошибки, в таком случае осуществляется выход на error, а в рег. a будет находиться:
1 - при переполнении числа; 2 - при делении на ноль. сюда следует вставить свою процедуру обработки ощибок, пока там ret.
перейдем к описанию процедур:
1. сложение двух ieee чисел. на входе: на стеке ieee число, к ко- торому нужно прибавить, а в de, hl - что прибавить. на выходе: de, hl - сумма чисел. пример: нужно сложить 2 и 10: ld de, #0100 ; это ld hl, #4000 ; число 2 push hl ; заносим push de ; на стек ld de, #0300 ; это ld hl, #5000 ; число 10 call ieee_add ... (обратите внимание как число зано- сится на стек, сначала hl, а потом de !) 2. разность двух ieee чисел. на входе: на стеке ieee число, от которого нужно отнять, а в de, hl - что отнять. на выходе: de, hl - разность чисел. пример: нужно отнять 1 от 2: ld de, #0100 ; это ld hl, #4000 ; число 2 push hl ; заносим push de ; на стек ld de, #0000 ; это ld hl, #4000 ; число 1 call ieee_sub ... 3. умножение двух ieee чисел. на входе: на стеке ieee число, кото- рое нужно умножить, а в de, hl - на что умножить. на выходе: de, hl - перемноженное число. пример: нужно умножить 10 на 2: ld de, #0300 ; это ld hl, #5000 ; число 10 push hl ; заносим push de ; на стек ld de, #0100 ; это ld hl, #4000 ; число 2 call ieee_mul ... 4. деление двух ieee чисел. на входе: на стеке ieee число, кото- рое нужно разделить, а в de, hl - на что раделить. на выходе: de, hl - разделенное чис- ло. пример: нужно разделить 10 на 2: ld de, #0300 ; это ld hl, #5000 ; число 10 push hl ; заносим push de ; на стек ld de, #0100 ; это ld hl, #4000 ; число 2 call ieee_div ... 5. перевод из формата int в формат ieee. на входе: в hl - число для перево- да. на выходе: de, hl - ieee число. пример: нужно перевести число 20 в ieee формат: ld hl, 20 call int_ieee ... для числа -20 это: ld hl, -20 call int_ieee 6. перевод из формата ieee в формат int. на входе: de, hl - число для перево- да. на выходе: hl - int число. 7. возвращает целую часть от ieee числа в int форме в hl. на входе: de, hl - ieee число. на выходе: hl - int число. пример: ... ld de, num_1 ld hl, num_2 call ieee_trunc ... 8. косинус. на входе: de, hl - градус, заданный в радианах. на выходе: de, hl - косинус числа. пример: ... ld de, num_1 ld hl, num_2 call ieee_cos ... 9. синус. на входе: de, hl - градус, заданный в радианах. на выходе: de, hl - синус числа. пример: ... ld de, num_1 ld hl, num_2 call ieee_sin ... 10. квадрат числа. на входе: de, hl - число. на выходе: de, hl - квадрат числа. пример: ... ld de, num_1 ld hl, num_2 call ieee_square ... ну вот, вроде, и все, что надо для нормальной работы с данной библиотекой. до встречи в следующих номерах... +====== математическая библиотека =====+ | ### #### #### #### ** ** | | *#* #*** #*** #*** *** *** | | # # # # ** ** | | # ### ### ### * * ** ** | | # # # # * * ** ** | | *#* #*** #*** #*** * * ** ** | | ### #### #### #### * **** * **** | += 17-19.03.99 ===== maximum/integer + err_overflow equ 1 err_div_by_0 equ 2 error ret +--------------------------------------+ | ieee_add - сложение двух ieee чисел: | | ld de,num0_1 | | ld hl,num0_2 | | push hl | | push de | | ld de,num1_1 | | ld hl,num1_2 | | call ieee_add | +--------------------------------------+ ieee_add bit 6,h jp z,exit_2 ld iy,0 add iy,sp ld a,h ld b,(iy+5) bit 6,b jr z,ieee_a6 xor b push af push de ld a,d ld d,b ld b,e ld e,(iy+4) sub (iy+3) jp pe,ieee_a7 jp m,ieeea13 ld c,(iy+2) jr z,ieeea14 ieee_a1 push hl res 7,d res 7,h ieee_a2 srl d rr e rr c dec a jr nz,ieee_a2 ld a,b bit 7,(iy-1-1) jr nz,ieee_a8 ieee_a3 add a,c adc hl,de pop bc pop de jp po,ieee_a4 srl h rr l rra inc d jp pe,ieeea12 ieee_a4 ld e,a ld a,b and #80 or h ld h,a ieee_a5 pop af ieee_a6 pop bc pop af pop af push bc ret ieee_a7 pop de jr nc,exit_1 jr ieee_a5 ieee_a8 sub c sbc hl,de ieee_a9 pop bc ieeea10 pop de ieeea11 bit 6,h jr nz,ieee_a4 add a,a adc hl,hl dec d jp po,ieeea11 ieeea12 ld sp,iy pop bc pop hl pop hl push bc ieee_ov ld a,err_overflow jp error ieeea13 ld c,b ld b,(iy+3) ld (iy-3),b ld b,(iy+2) ex de,hl neg jr ieee_a1 ieeea14 ld a,b push hl res 7,h res 7,d bit 7,(iy-1) jr z,ieee_a3 sub c sbc hl,de jr nz,ieeea15 or a jr z,ieeea16 ieeea15 jr nc,ieee_a9 ld de,0 ex de,hl ld c,a pop af cpl ld b,a xor a sub c sbc hl,de jr ieeea10 ieeea16 ld d,h ld e,h pop af pop af jr ieee_a5 exit_1 pop af exit_2 pop bc pop de pop hl push bc ret +--------------------------------------+ | ieee_sub - разность двух ieee чисел: | | ld de,num0_1 | | ld hl,num0_2 | | push hl | | push de | | ld de,num1_1 | | ld hl,num1_2 | | call ieee_sub | +--------------------------------------+ ieee_sub ld a,#80 xor h ld h,a jp ieee_add +--------------------------------------+ | ieee_mul - перемножение ieee чисел: | | ld de,num0_1 | | ld hl,num0_2 | | push hl | | push de | | ld de,num1_1 | | ld hl,num1_2 | | call ieee_mul | +--------------------------------------+ ieee_mul ld iy,0 add iy,sp ld a,#40 and h ld b,(iy+5) and b jr z,ieee_m9 ld a,h xor b and #80 ld b,a ld a,(iy+3) add a,d ld c,a jp pe,ieeea12 push bc res 7,h ld c,e xor a ex de,hl ld l,(iy+2) ld b,8 ieee_m1 rr l jr nc,ieee_m2 add a,d ieee_m2 rra djnz ieee_m1 rr l ld h,a ld a,(iy+4) ld b,8 ieee_m3 rra jr nc,ieee_m4 add hl,de ieee_m4 rr h rr l djnz ieee_m3 rra ld b,7 ieee_m5 rr (iy+5) jr nc,ieee_m6 add a,c adc hl,de ieee_m6 rr h rr l rra djnz ieee_m5 pop bc ld e,a ld d,c bit 6,h jr nz,ieee_m7 rl e adc hl,hl jr ieee_m8 ieee_m7 inc d jp pe,ieeea12 ieee_m8 ld a,b or h ld h,a pop bc pop af pop af push bc ret ieee_m9 pop hl pop de ex (sp),hl ld hl,0 ld e,h ld d,l ret +--------------------------------------+ | ieee_div - деление двух ieee чисел: | | ld de,num0_1 | | ld hl,num0_2 | | push hl | | push de | | ld de,num1_1 | | ld hl,num1_2 | | call ieee_sub | +--------------------------------------+ ieee_div bit 6,h ld a,err_div_by_0 jp z,error ld iy,0 add iy,sp ld b,(iy+5) bit 6,b jp z,ieee_m9 ld a,(iy+3) sub d jp pe,ieeea12 push af ld d,b ld c,e ld e,(iy+4) ld a,d xor h and #80 res 7,d res 7,h push af ex de,hl ld a,(iy+2) ld b,#08 ieee_d1 sub c sbc hl,de jr nc,ieee_d2 add a,c adc hl,de ieee_d2 rl (iy-4) add a,a adc hl,hl djnz ieee_d1 ld b,8 ieee_d3 sbc hl,de jr nc,ieee_d4 add hl,de ieee_d4 rla add hl,hl djnz ieee_d3 cpl ieee_d5 ld l,a ld a,h ld b,8 ieee_d6 sub d jr nc,ieee_d7 add a,d ieee_d7 rl e add a,a djnz ieee_d6 pop bc ld a,c cpl ld h,a ld a,e pop de cpl bit 7,h jr nz,ieee_d9 dec d jp pe,ieeea12 ieee_d8 ld e,a ld a,h or b ld h,a pop bc pop af pop af push bc ret ieee_d9 srl h rr l rra jr ieee_d8 +--------------------------------------+ | int_ieee - перевод числа из формата | | int в формат ieee: | | ld hl,num | | call int_ieee | | на выходе: de,hl - ieee число | +--------------------------------------+ int_ieee ld a,#80 and h jp z,i_ieee1 ex de,hl ld hl,0 sbc hl,de or a i_ieee1 ld de,0 adc hl,de ret z ld d,14 i_ieee2 bit 6,h jp nz,i_ieee3 add hl,hl dec d jp i_ieee2 i_ieee3 ld e,0 or h ld h,a ret +--------------------------------------+ | ieee_int - перевод числа из формата | | ieee в число формата int: | | ld de,num_1 | | ld hl,num_2 | | call ieee_int | | на выходе: hl - int число | +--------------------------------------+ ieee_int push hl push de ld de,#ff00 ld hl,#4000 call ieee_add bit 6,h ret z ld a,#80 and h ld c,a res 7,h ld a,d or a jp m,ieee_i5 ld a,#0e sub d jp c,ieee_ov ld b,a xor a cp e jp z,ieee_i1 inc a ieee_i1 dec b inc b jp z,ieee_i3 ieee_i2 srl h rr l adc a,0 djnz ieee_i2 ieee_i3 inc c ret p or a jp z,ieee_i4 inc hl ieee_i4 ex de,hl ld hl,0 sbc hl,de ret ieee_i5 inc c ld hl,0 ret p dec hl ret +--------------------------------------+ | ieee_trunc - возвращает целую часть | | от ieee числа в int форме в hl | | ld de,num_1 | | ld hlhl,num_2 | | call ieee_trunc | | на выходе: hl - int число | +--------------------------------------+ ieee_trunc bit 6,h ret z ld a,#80 and h ld c,a res 7,h ld a,14 sub d jr z,ieee_t2 jp m,ieee_t3 ld b,a ieee_t1 srl h rr l djnz ieee_t1 ieee_t2 inc c ret p ex de,hl ld hl,0 or a sbc hl,de ret ieee_t3 ld hl,0 ret +--------------------------------------+ | ieee_cos - косинус числа: | | число задается в радианах ! | | ld de,num_1 | | ld hl,num_2 | | call ieee_cos | | на выходе: de,hl - число | +--------------------------------------+ ieee_cos bit 6,h jp z,ieee_null ld a,d cp #f3 jp m,ieee_null call ieee_c0 ld b,#00 jr nz,ieee_c1 ld b,#80 call ieee_c2 ieee_c1 ld a,d add a,#02 ex af,af' ld a,#02 jr ieee_s1 +--------------------------------------+ | ieee_sin - синус числа: | | число задается в радианах ! | | ld de,num_1 | | ld hl,num_2 | | call ieee_sin | | на выходе: de,hl - число | +--------------------------------------+ ieee_sin bit 6,h ret z ld a,d cp #f3 ret m push hl call ieee_c0 jr nz,ieee_s0 call ieee_c2 xor a ieee_s0 ex af,af' xor a pop bc ieee_s1 ex af,af' xor b cpl and #80 ld (d31),a ld a,d cp #fe call z,ieee_c2 ex af,af' add a,a ex af,af' cp #fd jr nz,$+5 call ieee_c2 cp #fc ex af,af' add a,a ex af,af' jr nz,ieee_s2 ex af,af' inc a ex af,af' ld bc,#4000 push bc ld b,#fd push bc set 7,h call ieee_add ieee_s2 ex af,af' exx ld l,a ld h,0 ld de,sin_tab add hl,de ld a,(hl) ld (d32),a exx ld (d33),de ld (d35),hl call ieee_square push hl push de ld bc,#7a3b push bc ld bc,#0021 push bc ld bc,#4d67 push bc ld bc,#0157 push bc ld bc,#e144 push bc ld bc,#00b2 push bc call ieee_add call ieee_div call ieee_add ld (d3b),de ld (d3d),hl call ieee_div ld c,h ld a,h xor #80 ld h,a ld (d37),de ld (d39),hl ld h,c push hl push de ld de,(d3b) ld hl,(d3d) call ieee_add ld (d3f),de ld (d41),hl ld a,(d32) srl a jr c,ieee_s3 or a jr nz,ieee_s6 ld de,(d33) ld hl,(d35) inc d ieee_s4 call ieee_s8 ieee_s5 ld a,(d31) or h ld h,a ret ieee_s6 ld de,(d3b) ld hl,(d3d) push hl push de ld de,(d37) ld hl,(d39) call ieee_add jr ieee_s4 ieee_s3 ld hl,#5a82 ld de,#ff79 push hl push de inc d or a jr nz,$+4 set 7,h push hl push de ld de,(d37) ld hl,(d39) jr nz,ieee_s7 ld a,h xor #80 ld h,a ieee_s7 push hl push de ld hl,(d35) ld de,(d33) call ieee_add call ieee_mul call ieee_s8 call ieee_add jr ieee_s5 ieee_s8 push hl push de ld hl,(d41) ld de,(d3f) call ieee_div ret ieee_c2 ld a,e ieee_c3 dec d add a,a adc hl,hl jr z,ieee_c4 bit 6,h jr z,ieee_c3 ieee_c5 ld e,a ex af,af' inc a ex af,af' ld a,d ret ieee_c4 or a jr nz,ieee_c3 ld d,a jr ieee_c5 ieee_c0 push af res 7,h ld bc,#517c push bc ld bc,#fdc0 push bc call ieee_mul call ieee_q pop af ex af,af' ld a,d inc a ret sin_tab db 0,1,3,2,2,3,1,0,2,3,1,0,0,1,3,2 ieee_q ld a,h or a ret z jp m,ieee_q4 ieee_q1 bit 7,d ret nz ld b,d inc b ld a,e ieee_q2 add a,a adc hl,hl djnz ieee_q2 ld d,#ff res 7,h ld e,a ieee_q3 bit 6,h ret nz dec d sla e adc hl,hl jr nz,ieee_q3 inc e dec e jr nz,ieee_q3 ld d,e ret ieee_q4 res 7,h call ieee_q1 bit 6,h ret z set 7,h push hl push de ld hl,#4000 ld d,l ld e,l call ieee_add ret d31 db 0 d32 db 0 d33 dw 0 d35 dw 0 d37 dw 0 d39 dw 0 d3b dw 0 d3d dw 0 d3f dw 0 d41 dw 0 ieee_null ld hl,#4000 ld d,l ld e,l ret +--------------------------------------+ | ieee_square - квадрат числа | | ld de,num_1 | | ld hl,num_2 | | call ieee_square | | на выходе: de,hl - число | +--------------------------------------+ ieee_square pop bc push hl push de push bc jp ieee_mul