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