home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 364b.lha / PCQ_v1.1 / Runtime / PCQ / SinCos.asm < prev    next >
Encoding:
Assembly Source File  |  1990-04-08  |  6.3 KB  |  218 lines

  1. *
  2. *    SinCos.asm (of PCQ Pascal)
  3. *
  4. *    These routines replace earlier attempts at the sine and
  5. *    cosine functions.  They are based on the series
  6. *    representations of the functions, so they're much more
  7. *    accurate for most of the curve.
  8. *
  9. *    Martin Combs sent me a Pascal version of the implementation
  10. *    used here.  I had been looking at various series for exp()
  11. *    and ln(), but I didn't like the algorithms I was coming up
  12. *    with for sine and cosine.  Thus I appreciate Martin's
  13. *    contribution.
  14. *
  15. *    Martin's original Pascal functions duplicated by the assembly
  16. *    below are:
  17. *
  18. * FUNCTION sine(x:REAL):REAL;
  19. *   FUNCTION GetVal : REAL;
  20. *     CONST rfac2 = 0.5;        {rfac stands for reciprocal of factorial}
  21. *           rfac3 = 0.1666667;
  22. *           rfac4 = 0.0416667;
  23. *           rfac5 = 0.0083333;
  24. *           sincosfourthpi = 0.7071068; {sine or cosine of pi/4}
  25. *     VAR   x2 : REAL;
  26. * {This variation gives four significant figure accuracy}
  27. *   BEGIN
  28. *     IF x>fourthpi THEN BEGIN   { if x in second octant }
  29. *       x:=x-fourthpi;           { reduce x to first octant }
  30. *       x2:=sqr(x);
  31. *       x2:=x2*(rfac4*x2-rfac2)+1.0; {calculates cosine in first octant}
  32. *    { above is cos(x)=1-(x^2)/2!+(x^4)/4! }
  33. *       GETVAL:=sincosfourthpi*(sine(x)+x2)  { note the recursion }
  34. * { Note: sin(x)=sin((x-pi/4)+pi/4)=sin(x-pi/4)cos(pi/4)+cos(x-pi/4)sin(pi/4)}
  35. * { =.7071068(sin(x-pi/4)+cos(x-pi/4)) }
  36. *     END ELSE
  37. *     x2:=sqr(x);
  38. *     GetVal:=x*(x2*(rfac5*x2-rfac3)+1.0)   {calculates sine in first octant}
  39. *  {above is sin(x)=x-(x^3)/3!+(x^5)/5! }
  40. *   END;
  41. * {This variation gives two significant figure accuracy, but faster}
  42. * {  BEGIN
  43. *     IF x>fourthpi THEN BEGIN
  44. *       x:=x-fourthpi;
  45. *       x2:=sqr(x);
  46. *       GetVal:=sincosfourthpi*(sine(x)+1.0-rfac2*x2)  }
  47. * {cosine portion of above is 1-(x^2)/2! }
  48. * {    END ELSE
  49. *     x2:=sqr(x);
  50. *     GetVal:=x*(1.0-rfac3*x2)
  51. *   END;   }
  52. * BEGIN
  53. *   IF (x>twopi) OR (x<0.0) THEN  { faster than always doing it }
  54. *     x:= x-Floor(x/twopi)*twopi;
  55. *   IF x<halfpi THEN          { first quadrant }
  56. *     sine:=GetVal
  57. *   ELSE IF x<pi THEN BEGIN   { second quadrant }
  58. *     x:=pi-x;
  59. *     sine:=GetVal
  60. *   END ELSE IF x<threehalvespi THEN BEGIN   { third quadrant }
  61. *     x:=x-pi;
  62. *     sine:=-GetVal
  63. *   END ELSE BEGIN            { fourth quadrant }
  64. *     x:=twopi-x;
  65. *     sine:=-GetVal
  66. *   END
  67. * END;
  68. * FUNCTION cosine(x:REAL):REAL;
  69. * BEGIN
  70. *   cosine:=sine(halfpi-x)
  71. * END;
  72. *
  73.  
  74.     XREF    _p%MathBase
  75.  
  76.     XREF    _LVOSPAdd
  77.     XREF    _LVOSPSub
  78.     XREF    _LVOSPMul
  79.     XREF    _LVOSPFloor
  80.     XREF    _LVOSPCmp
  81.     XREF    _LVOSPNeg
  82.     XREF    _LVOSPDiv
  83.  
  84. *
  85. *    GetVal returns the sine of theta, held in d0, which is
  86. *    an angle between 0 and Pi/2
  87. *
  88.  
  89. GetVal
  90.     move.l    d0,-(sp)    ; save theta
  91.     move.l    #$C90FD940,d1    ; d1 := pi/4
  92.     jsr    _LVOSPCmp(a6)    ; compare 'em
  93.     ble    FirstOctant    ; if theta <= pi/4, skip this
  94.  
  95.     move.l    (sp),d0        ; d0 := theta
  96.     move.l    #$C90FD940,d1    ; d1 := pi/4
  97.     jsr    _LVOSPSub(a6)    ; d0 := theta - pi/4
  98.     move.l    d0,(sp)        ; save new theta
  99.     move.l    d0,d1        ; set up for square
  100.     jsr    _LVOSPMul(a6)    ; d0 := theta squared
  101.     move.l    d0,-(sp)    ; save theta2
  102.  
  103.     move.l    #$AAAAB33C,d1    ; d1 := 1/4!
  104.     jsr    _LVOSPMul(a6)    ; d0 := theta^2 * 1/4!
  105.     move.l    #$80000040,d1    ; d1 := 1/2!
  106.     jsr    _LVOSPSub(a6)    ; d0 := theta^2 * 1/4! - 1/2!
  107.     move.l    (sp)+,d1    ; d1 := theta^2
  108.     jsr    _LVOSPMul(a6)    ; d0 := t^2 * (t^2/4! - 1/2!) = t^4/4! - t^2/2!
  109.     move.l    #$80000041,d1    ; d1 := 1.0
  110.     jsr    _LVOSPAdd(a6)    ; d0 := everything + 1.0
  111.  
  112.     move.l    d0,-(sp)    ; save this result
  113.     move.l    4(sp),-(sp)    ; put theta back on stack
  114.     bsr    _p%sin        ; call sine recursively
  115.     addq.l    #4,sp        ; and pop it back off
  116.     move.l    (sp)+,d1    ; get theta^2
  117.     jsr    _LVOSPAdd(a6)    ; add them
  118.     move.l    #$B504F440,d1    ; d1 := sin(pi/4)
  119.     jsr    _LVOSPMul(a6)    ; multiply by sin(pi/4)
  120.     addq.l    #4,sp        ; pop previous theta
  121.     rts            ; and return
  122.  
  123. FirstOctant
  124.     move.l    (sp),d0        ; d0 := theta
  125.     move.l    d0,d1        ; so does d1
  126.     jsr    _LVOSPMul(a6)    ; d0 := theta^2
  127.     move.l    d0,-(sp)    ; save this
  128.  
  129.     move.l    #$8888653A,d1    ; d1 := 1/5! = 1/96
  130.     jsr    _LVOSPMul(a6)    ; d0 := theta^2 * 1/5!
  131.     move.l    #$AAAAAD3E,d1    ; d1 := 1/3!
  132.     jsr    _LVOSPSub(a6)    ; d0 := theta^2/5! - 1/3!
  133.     move.l    (sp)+,d1    ; pop theta^2
  134.     jsr    _LVOSPMul(a6)    ; d0 := theta^4/5! - theta^2/3!
  135.     move.l    #$80000041,d1    ; d1 := 1.0
  136.     jsr    _LVOSPAdd(a6)    ; d0 := above + 1.0
  137.     move.l    (sp)+,d1    ; d1 := theta
  138.     jmp    _LVOSPMul(a6)    ; d0 := theta - theta^3/3! + theta^5/5!
  139.                 ; return with that value
  140.  
  141.  
  142. * d0 contains the angle, which is also on the stack
  143.  
  144.     XDEF    _p%sin
  145. _p%sin
  146.     move.l    _p%MathBase,a6    ; we'll use this all over
  147.     move.l    #$C90FD943,d1    ; d1 := 2Pi
  148.     jsr    _LVOSPCmp(a6)    ; compare theta and 2Pi
  149.     bgt.s    ShrinkIt    ; normalize to 0 <= theta <= 2Pi
  150.     move.l    4(sp),d0    ; d0 := theta
  151.     moveq.l    #0,d1        ; d1 := 0.0
  152.     jsr    _LVOSPCmp(a6)    ; compare theta & 0.0
  153.     bge.s    AfterShrink    ; don't bother with normalization
  154. ShrinkIt
  155.     move.l    4(sp),d0    ; d0 := theta
  156.     move.l    #$C90FD943,d1    ; d1 := 2Pi
  157.     jsr    _LVOSPDiv(a6)    ; d0 := theta / 2Pi
  158.     jsr    _LVOSPFloor(a6)    ; d0 := |_theta / 2Pi_| ( floor )
  159.     move.l    #$C90FD943,d1    ; d1 := 2Pi
  160.     jsr    _LVOSPMul(a6)    ; d0 := floor * 2Pi
  161.     move.l    d0,d1        ; shift for upcoming subtract
  162.     move.l    4(sp),d0    ; d0 := theta
  163.     jsr    _LVOSPSub(a6)    ; d0 := x - the rest
  164.     move.l    d0,4(sp)    ; save as new theta, and fall through
  165.  
  166. AfterShrink
  167.     move.l    4(sp),d0    ; for not normalized case
  168.     move.l    #$C90FD941,d1    ; d1 := Pi/2
  169.     jsr    _LVOSPCmp(a6)    ; compare theta and Pi/2
  170.     bge.s    NotFirst    ; it's not in first quadrant
  171.     move.l    4(sp),d0    ; get theta
  172.     bra    GetVal        ; get value and leave
  173.  
  174. NotFirst
  175.     move.l    #$C90FD942,d1    ; d1 := Pi
  176.     move.l    4(sp),d0    ; d0 := theta
  177.     jsr    _LVOSPCmp(a6)    ; compare these
  178.     bge.s    NotSecond    ; it's not in first or second
  179.  
  180.     move.l    #$C90FD942,d0    ; d1 := Pi
  181.     move.l    4(sp),d1    ; d0 := theta
  182.     jsr    _LVOSPSub(a6)    ; d0 := Pi - theta
  183.     bra    GetVal        ; get value and leave
  184.  
  185. NotSecond
  186.     move.l    #$96CBE343,d1    ; d1 := 3Pi/2
  187.     move.l    4(sp),d0    ; d0 := theta
  188.     jsr    _LVOSPCmp(a6)    ; compare theta & 3Pi/2
  189.     bge    FourthQuad    ; definitely
  190.  
  191.     move.l    4(sp),d1    ; d1 := theta
  192.     move.l    #$C90FD942,d0    ; d0 := Pi
  193.     jsr    _LVOSPSub(a6)    ; d0 := Pi - theta
  194.     bra    GetVal        ; get value, and return
  195.  
  196. FourthQuad
  197.     move.l    #$C90FD943,d0    ; d0 := 2Pi
  198.     move.l    4(sp),d1    ; d1 := theta
  199.     jsr    _LVOSPSub(a6)    ; d0 := 2Pi - theta
  200.     bsr    GetVal        ; get sine here
  201.     jmp    _LVOSPNeg(a6)    ; return negative
  202.  
  203.     XDEF    _p%cos
  204. _p%cos
  205.     move.l    _p%MathBase,a6
  206.     move.l    4(sp),d1    ; d1 := theta
  207.     move.l    #$C90FD941,d0    ; d0 := Pi/2
  208.     jsr    _LVOSPSub(a6)    ; d0 := Pi/2 - theta
  209.     move.l    d0,4(sp)    ; save as new theta
  210.     bra    _p%sin        ; call sin, leave from there
  211.  
  212.     END
  213.