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