home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pcmagazi / 1990 / 05 / pp905 / ftrig.asm < prev    next >
Assembly Source File  |  1989-10-26  |  11KB  |  294 lines

  1.         title   FTRIG.ASM 80x87 Sine, Cosine, Tangent
  2.         page    55,132
  3.  
  4. ; FTRIG.ASM --- 80x87 Sine, Cosine, Tangent Functions
  5. ;
  6. ; Copyright (C) 1989 Ziff Davis Communications
  7. ; PC Magazine * Ray Duncan
  8. ;
  9. ; Procedure FSIN calculates sine(x)
  10. ; Procedure FCOS calculates cosine(x)
  11. ; Procedure FTAN calculates tangent(x) 
  12. ;
  13. ; All three procedures have the same calling sequence:
  14. ;
  15. ; Call with:    ST(0)     = argument in radians
  16. ;
  17. ; Returns:      ST(0)     = result
  18. ;
  19. ; Uses:         AX, BX.  Other registers preserved.
  20. ;
  21. ; Make sure coprocessor has been properly initialized
  22. ; with a previous call to INIT87!
  23.  
  24. _DATA   segment word public 'DATA'
  25.  
  26. piby2   dq      3ff921fb54442d18h       ; constant pi / 2
  27. piby4   dq      3fe921fb54442d18h       ; constant pi / 4
  28.  
  29. plusinf dd      07f800000h              ; +infinity encoding
  30. neginf  dd      0ff800000h              ; -infinity encoding
  31.  
  32. oldcw   dw      0                       ; old control word
  33. newcw   dw      0                       ; new control word
  34.  
  35. temp    dw      0                       ; scratch storage
  36.  
  37. cctab   db      0,4,1,5,2,6,3,7         ; relates condition code
  38.                                         ; bits to octant numbers
  39.  
  40. fsintab label   word                    ; sine dispatch table
  41.         dw      fsin0                   ; octant 0
  42.         dw      fsin1                   ; octant 1
  43.         dw      fsin2                   ; octant 2
  44.         dw      fsin3                   ; octant 3
  45.         dw      fsin4                   ; octant 4
  46.         dw      fsin5                   ; octant 5
  47.         dw      fsin6                   ; octant 6
  48.         dw      fsin7                   ; octant 7
  49.  
  50. ftantab label   word                    ; tangent dispatch table
  51.                                         ; for reduced angle <> 0
  52.         dw      ftan0                   ; octant 0
  53.         dw      ftan1                   ; octant 1
  54.         dw      ftan2                   ; octant 2
  55.         dw      ftan3                   ; octant 3
  56.         dw      ftan4                   ; octant 4
  57.         dw      ftan5                   ; octant 5
  58.         dw      ftan6                   ; octant 6
  59.         dw      ftan7                   ; octant 7
  60.  
  61. ftanztab label  word                    ; tangent dispatch table
  62.                                         ; for reduced angle = 0
  63.         dw      ftanz0                  ; octant 0
  64.         dw      ftanz1                  ; octant 1
  65.         dw      ftanz2                  ; octant 2
  66.         dw      ftanz3                  ; octant 3
  67.         dw      ftanz4                  ; octant 4
  68.         dw      ftanz5                  ; octant 5
  69.         dw      ftanz6                  ; octant 6
  70.         dw      ftanz7                  ; octant 7
  71.  
  72. _DATA   ends
  73.  
  74. _TEXT   segment word public 'CODE'
  75.  
  76.         assume  cs:_TEXT,ds:_DATA
  77.  
  78.         public  fsin
  79. fsin    proc    near                    ; calculate sine of ST(0)
  80.  
  81.         call    octant                  ; reduce angle, find octant
  82.         shl     bx,1                    ; form index to jump table
  83.         jmp     [bx+fsintab]            ; branch to correct sequence
  84.  
  85. fsin0:  call    psin                    ; octant 0
  86.         ret                             ; sin(x) = psin(x)
  87.  
  88. fsin1:  fsubr   piby4                   ; octant 1
  89.         call    pcos                    ; sin(x) = pcos((pi/4)-x)
  90.         ret
  91.  
  92. fsin2:  call    pcos                    ; octant 2
  93.         ret                             ; sin(x) = pcos(x)
  94.  
  95. fsin3:  fsubr   piby4                   ; octant 3
  96.         call    psin                    ; sin(x) = psin((pi/4)-x)
  97.         ret
  98.  
  99. fsin4:  call    psin                    ; octant 4
  100.         fchs                            ; sin(x) = -(psin(x))
  101.         ret
  102.  
  103. fsin5:  fsubr   piby4                   ; octant 5
  104.         call    pcos                    ; sin(x) = -(pcos((pi/4)-x)
  105.         fchs
  106.         ret
  107.  
  108. fsin6:  call    pcos                    ; octant 6
  109.         fchs                            ; sin(x) = -(pcos(x))
  110.         ret
  111.  
  112. fsin7:  fsubr   piby4                   ; octant 7
  113.         call    psin                    ; sin(x) = -(psin((pi/4)-x))
  114.         fchs
  115.         ret
  116.  
  117. fsin    endp
  118.  
  119.  
  120.         public  fcos
  121. fcos    proc    near                    ; calculate cosine of ST(0)
  122.  
  123.         call    octant                  ; reduce angle, find octant
  124.         add     bx,2                    ; add pi/2 (90 degrees) and
  125.         and     bx,7                    ; then use sine routines
  126.         shl     bx,1                    ; form index to jump table
  127.         jmp     [bx+fsintab]            ; branch to correct sequence
  128.  
  129. fcos    endp
  130.  
  131.  
  132.         public  ftan
  133. ftan    proc    near                    ; calculate tangent of ST(0)
  134.  
  135.         call    octant                  ; reduce angle, find octant     
  136.         shl     bx,1                    ; form index for jump table
  137.         ftst                            ; is reduced angle = 0?
  138.         fstsw   temp
  139.         fwait
  140.         mov     ax,temp
  141.         sahf
  142.         je      ftanz                   ; reduced angle = 0
  143.         jmp     [bx+ftantab]            ; reduced angle <> 0
  144.  
  145. ftan0:                                  ; octant 0
  146. ftan4:                                  ; octant 4      
  147.         fptan                           ; get Y/X
  148.         fdivp   st(1),st(0)
  149.         ret
  150.  
  151. ftan1:                                  ; octant 1
  152. ftan5:                                  ; octant 5
  153.         fsubr   piby4                   ; (pi/4) - angle
  154.         fptan                           ; get (Y/X)
  155.         fdivp   st(1),st(0)             ; 1/(Y/X)
  156.         fld1
  157.         fdivrp  st(1),st(0)
  158.         ret
  159.  
  160. ftan2:                                  ; octant 2
  161. ftan6:                                  ; octant 6
  162.         fptan                           ; get Y/X
  163.         fdivp   st(1),st(0)
  164.         fld1                            ; -(1/(Y/X))
  165.         fdivrp  st(1),st(0)
  166.         fchs
  167.         ret
  168.  
  169. ftan3:                                  ; octant 3
  170. ftan7:                                  ; octant 7
  171.         fsubr   piby4                   ; (pi/4) - angle
  172.         fptan                           ; get Y/X
  173.         fdivp   st(1),st(0)             ; -(Y/X)
  174.         fchs
  175.         ret
  176.  
  177. ftanz:                                  ; reduced angle = 0
  178.         fstp    st(0)                   ; discard angle and
  179.         jmp     [bx+ftanztab]           ; go load special value
  180.  
  181. ftanz0: fldz                            ; 0 degrees
  182.         ret                             ; load constant 0
  183.  
  184. ftanz1: fld1                            ; 45 degrees
  185.         ret                             ; load constant 1
  186.  
  187. ftanz2: fld     plusinf                 ; 90 degrees
  188.         ret                             ; load constant +infinity
  189.  
  190. ftanz3: fld1                            ; 135 degrees
  191.         fchs                            ; load constant -1
  192.         ret
  193.  
  194. ftanz4: fldz                            ; 180 degrees
  195.         ret                             ; load constant 0
  196.  
  197. ftanz5: fld1                            ; 225 degrees
  198.         ret                             ; load constant 1
  199.  
  200. ftanz6: fld     neginf                  ; 270 degrees
  201.         ret                             ; load constant -infinity
  202.  
  203. ftanz7: fld1                            ; 315 degrees
  204.         fchs                            ; load constant -1
  205.         ret
  206.  
  207. ftan    endp
  208.  
  209. ;
  210. ; PSIN:         Partial sine
  211. ; Call with:    ST(0) = angle in range 0 <= x < pi/4
  212. ; Returns:      ST(0) = sine
  213. ;
  214. psin    proc    near
  215.                                         
  216.         fptan                           ; get fraction Y/X
  217.         fld     st(1)                   ; sin = Y/sqrt(X*X+Y*Y)
  218.         fmul    st(0),st(0)             
  219.         fxch    st(1)
  220.         fmul    st(0),st(0)
  221.         faddp   st(1),st(0)
  222.         fsqrt              
  223.         fdivp   st(1),st(0)
  224.         ret                             ; leave divide running  
  225.  
  226. psin    endp
  227.  
  228. ;
  229. ; PCOS:         Partial cosine
  230. ; Call with:    ST(0) = angle in range 0 <= x < pi/4
  231. ; Returns:      ST(0) = cosine
  232. ;
  233. pcos    proc    near
  234.  
  235.         fptan                           ; get fraction Y/X
  236.         fxch    st(1)                   ; cos = X/sqrt(X*X+Y*Y)
  237.         fld     st(1)
  238.         fmul    st(0),st(0)
  239.         fxch    st(1)
  240.         fmul    st(0),st(0)
  241.         faddp   st(1),st(0)
  242.         fsqrt
  243.         fdivp   st(1),st(0)
  244.         ret                             ; leave divide running
  245.  
  246. pcos    endp
  247.  
  248. ;
  249. ; OCTANT:       Find octant occupied by angle.
  250. ; Call with:    ST(0) = angle in radians
  251. ; Returns:      ST(0) = reduced angle, 0 <= angle < pi/4
  252. ;               BX    = octant(0-7)
  253. ;
  254. octant  proc    near
  255.  
  256.         push    ax                      ; save register
  257.         ftst                            ; test sign of angle
  258.         fstsw   temp                    ; unload FTST status
  259.         fabs                            ; force angle positive
  260.         push    temp                    ; save FTST status
  261.         fld     piby4                   ; load constant pi/4
  262.         fxch    st(1)                   ; put angle on top
  263.         fprem                           ; reduce to 0<=angle<pi/4
  264.         fstsw   temp                    ; unload FPREM status
  265.         fwait                           ; wait till it arrives
  266.         mov     bx,temp                 ; retrieve status word
  267.         and     bx,4300h                ; shift C3, C1, C0 status
  268.         rol     bx,1                    ; bits (which contain 
  269.         rol     bx,1                    ; low 3 bits of quotient
  270.         shl     bh,1                    ; from FPREM) to form
  271.         shl     bh,1                    ; index in range 0-7,
  272.         shl     bh,1                    ; then look up octant
  273.         shl     bh,1
  274.         rol     bx,1
  275.         rol     bx,1
  276.         mov     bl,[bx+cctab]           ; now BX = actual octant
  277.         pop     ax                      ; get back FTST status
  278.         sahf                            ; force CPU flags
  279.         jae     oct1                    ; jump, orig. angle >= 0
  280.         fsubr   st(0),st(1)             ; angle was negative,
  281.         sub     bx,7                    ; adjust reduced angle
  282.         neg     bx                      ; and octant
  283.  
  284. oct1:   fstp    st(1)                   ; discard pi/4 constant
  285.         pop     ax                      ; restore register, return
  286.         ret                             ; BX=octant, ST(0)=angle
  287.  
  288. octant  endp
  289.  
  290. _TEXT   ends
  291.  
  292.         end
  293.  
  294.