home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 141_01 / cmath.c < prev    next >
Text File  |  1985-03-10  |  15KB  |  471 lines

  1. /* cmath.c 1984 apr 30 pmk - 
  2.     combine fpsqrt + clogs + ctrig 
  3.     move consts to float.h & coef's to coef.h
  4.     speedup inner eval loops */
  5. #include "float.h"
  6. #include "coef.h"
  7.  
  8. char *fpsqrt (z, xin) char *z, *xin ; {    /* z = sqrt (x)    */
  9. #define ITS 6    /* iteration count */
  10.     float x, z2, x2 ;    unsigned n ;
  11.     fpasg (z, xin) ; fpasg (x, xin) ; 
  12.     z[4] = (z[4] >> 1) | (0x80 & z[4]) ;
  13.     for (n = ITS ; n ; --n)     {
  14.         /* Newton - Raphson, ITS iterations */
  15.         fpdiv (z2, x, z) ;    /* z2 = x / z ; */
  16.         fpadd (z, z, z2) ;    /* z += z2 ;    */
  17.         fpmult (z, HALF, z) ;    /* z *= half ;  */
  18.     } /* for ITS */
  19.     return z ;
  20. #undef ITS
  21. } /* fpsqrt */
  22.  
  23.  /* CTRIG.C *****
  24.     sine, cosine, tangent and arctangent
  25.     convert degrees to radians, convert radians to degrees
  26. These functions are discussed in detail in CTRIG.DOC
  27.  
  28. L. C. Calhoun
  29. 257 South Broadway
  30. Lebanon, Ohio 45036   513 932 4541/433 7510
  31.   */
  32.  
  33. /* simple ones first converting degrees - radians */
  34.  
  35. char *degtorad(rad,deg) /*obvious arguments in 5 char fp */
  36. char *rad, *deg;
  37. {
  38.     char *fpmult();
  39.     fpmult(rad,deg,RADINDEG);
  40.     return (rad);
  41. } /* degtorad */
  42.  
  43. char *radtodeg(deg,rad) /* 5 char fp arguments */
  44. char *deg, *rad;
  45. {
  46.     char *fpmult();
  47.     fpmult(deg,rad,DEGINRAD);
  48.     return (deg);
  49. } /* radtodeg */
  50.  
  51. /* service function sinev which evaluates when range of angle
  52. reduced to plus or minus pi/2 (90 deg) */
  53. char *sinev(result,x)    char *result, x[5];    {
  54.     char *fpmult(),xsq[5];    char *coef[5];
  55.     char *fpadd(),*fpasg();
  56.     int index;
  57.  
  58.     /*  use the exponent part of the floating point
  59.         to check for threat of underflow  use small
  60.         angle approximation if appropriate  */
  61.     if ( (x[4] > 128) && (x[4] < 226) )
  62.        {fpasg(result,x);       return (result);
  63.       }   /* solution to fpmult underflow problem */
  64.  
  65. /* series coef are 1., -.1666666, .008333026, -.0001980742,
  66.     .000002601887  determined from coefset program */
  67.     coef[0] = SINC0 ;    coef[1] = SINC1 ;
  68.     coef[2] = SINC2 ;    coef[3] = SINC3 ;
  69.     coef[4] = SINC4 ;    fpmult(xsq,x,x) ;
  70.  /* to this point the coef have been initialized, 
  71.     x squared computed. */
  72.  
  73. /* now to do the polynomial approximation */
  74.     fpasg (result, coef[4]) ;
  75.     for (index = 3 ; 0 <= index ; --index) {
  76.         fpadd (result, coef[index],
  77.             fpmult (result, result, xsq)) ;
  78.     } /* this loop approx 1/3 faster than original */
  79.     fpmult (result, result, x) ;
  80.     return (result);
  81. } /* sinev */
  82.  
  83.  /* here is sine(result,angle) with angle in radians */
  84. char *sine(result,angle)    char *result, *angle;    {
  85.     char *fpmult(),*twopi,*halfpi;
  86.     char *mtwopi,*mhalfpi,*fpasg(),*fpchs();
  87.     char *pi,*sinev(),*fpadd();    char y[5],*fpsub();
  88.     int fpcomp(), compar;    int signsine;
  89.  /* some initialization required here */
  90.     signsine = 1;
  91.     twopi    = TWOPI ;    halfpi    = HALFPI ;
  92.     pi    = PI ;        mtwopi    = MTWOPI ;
  93.     mhalfpi    = MHALFPI ;    fpasg(y,angle);
  94.     while (fpcomp(y,twopi) >= 0)
  95.        fpsub(y,y,twopi);
  96.     while (fpcomp(y,mtwopi)<= 0)
  97.        fpadd(y,y,twopi);
  98.     if(fpcomp(y,halfpi) > 0)
  99.        { signsine *=-1; fpsub (y,y,pi);       }
  100.     if(fpcomp(y,mhalfpi)<  0)
  101.        { signsine *=-1; fpadd (y,y,pi);       }
  102.     sinev(result,y);
  103.     if (signsine > 0) return (result);
  104.  /* minus so need to change sign */
  105.     else return ( fpchs(result,result) );
  106. } /* sine */
  107.  
  108.  /* cosine(result,angle) with angle in radians  - uses sine */
  109. char *cosine(result,angle)    char *result, *angle;    {
  110.     char *sine(),*fpsub(),y[5];
  111.     fpsub(y,HALFPI,angle);
  112.     sine(result,y);
  113.     return (result);
  114. } /* cosine */
  115.  
  116. /* tangent(result,angle) with angle in radians, returns very 
  117. large number for divide by zero condition */
  118. char *tangent(result,angle)    char *result, angle[5];    {
  119.     char *sine(), *cosine(), *fpdiv(), zero[5];
  120.     char sresult[5], cresult[5], intres[5], big[5];
  121.     char *fpmult(), *fpmag();
  122.  
  123.     sine(sresult,angle);
  124.     cosine(cresult,angle);
  125.     /* check magnitude of denominator :*/
  126.     /* check magnitude of denominator using exponent */
  127.     if ( (cresult[4] > 128) && (cresult[4] < 132) )
  128.        {initb(big,"30,207,228,127,128"); /*big number */
  129.         if ( sresult[3] > 127 ) /*use mantissa sign */
  130.            return ( fpchs(result,big) );
  131.         else return ( fpasg(result,big) );
  132.        }
  133.     /* check for small angle, use small angle approx to
  134.        avoid underflow */
  135.     if ( (angle[4] < 226) && (angle[4] > 128) )
  136.        return ( fpasg(result,angle) );
  137.     else
  138.        return ( fpdiv(result,sresult,cresult) );
  139. } /* tangent */
  140.  
  141. /* atanev(result,x) evaluates arctangent for 0 <= x < infinity,
  142.     result in radians */
  143. char *atanev(result,x)    char  result[5], x[5];    {
  144.     char *coef[8],y[5];    int index;
  145.     char *fpadd(),*fpmult(),*atof(),ysq[5];
  146.     char yterm[5],termreslt[5],*fpasg();
  147.  
  148.     /* small angle approximation */
  149.     if ( (x[4] > 128) && (x[4] < 226) )
  150.     /* use fp exponent to check size, use small angle */
  151.      return ( fpasg(result,x) );
  152.  
  153.     fpasg(result,PIOVER4);
  154.     /* check for argument near one */
  155.     fpsub(yterm,x,ONE);
  156.     if ( (yterm[4] > 128) && (yterm[4] < 243) )
  157.        return (result);
  158.  
  159.     coef[0] = ATNC0 ;    coef[1] = ATNC1 ;
  160.     coef[2] = ATNC2 ;    coef[3] = ATNC3 ;
  161.     coef[4] = ATNC4 ;    coef[5] = ATNC5 ;
  162.     coef[6] = ATNC6 ;    coef[7] = ATNC7 ;
  163.  
  164.     fpadd(termreslt,x,ONE);
  165.     fpdiv(y,yterm,termreslt);
  166.     fpmult(ysq,y,y);
  167.  /* do poly evaluation, fast loop */
  168.     for (index = 6, fpasg (result, coef[7]) ; 0 <= index ;
  169.         --index)
  170.         fpadd (result, coef[index], 
  171.             fpmult (result, result, ysq)) ;
  172.     fpadd (result, PIOVER4, fpmult (result, result, y) ) ;
  173.     return (result);
  174. } /* atanev */
  175.  
  176. /* arctan(result,angle) is floating point arctangent evaluation */
  177. char *arctan(result,x)    char result[5], x[5];    {
  178.     char *atanev(),*fpasg(),y[5];
  179.     char *fpchs();    int index;
  180.     /* check exponent for very large argument */
  181.     if ( (x[4] > 100) && (x[4] <= 128) )
  182.         fpasg(result,HALFPI);
  183.     else  /* go through evaluation */
  184.       { fpmag(y,x);   atanev(result,y);  }
  185.  
  186.     if ( x[3] > 127 )
  187.        return ( fpchs(result,result) ); 
  188.     else return (result);
  189. } /* arctan */
  190.  
  191. char *arctan2 (result, quadrant, opside, adjside)
  192. char result[5], opside[5], adjside[5];    int *quadrant;    {
  193.     char x[5], *fpmag(), *fpchs(); *arctan();
  194.     int opsign, adjsign;
  195.     char *zero ;    zero = ZERO ;
  196.  
  197.     opsign = fpcomp(opside,zero);
  198.     adjsign = fpcomp(adjside,zero);
  199.  
  200.     if((adjsign == 0) && (opsign == 0))
  201.        { *quadrant = 0;    fpasg(result,zero);
  202.         return(result);   }
  203.  
  204.     if ( ( (128 < adjside[4]) && (adjside[4] < 226) ) 
  205.     || (adjsign == 0) )
  206.        fpasg(result,HALFPI);
  207.     else
  208.        { fpdiv(x,opside,adjside);
  209.         fpmag(x,x);    arctan(result,x);   }
  210.  
  211.     if ( (adjsign == 0) && (opsign >  0) )
  212.        { *quadrant = 1;    return(result);   }
  213.     if ( (adjsign == 0) && (opsign <  0) )
  214.        { *quadrant = 4;    fpchs(result,result);
  215.         return(result);   }
  216.     if ( (adjsign >  0) && (opsign == 0) )
  217.        { *quadrant = 1;    return(result);   }
  218.     if ( (adjsign < 0 ) && (opsign == 0) )
  219.        { *quadrant = 2;    fpchs(result,result);
  220.         return(result);   }
  221.     if ( (adjsign > 0) && (opsign > 0) )
  222.        { *quadrant = 1;    return(result);   }
  223.     if ( (adjsign > 0) && (opsign < 0) )
  224.        { *quadrant = 4;    fpchs(result,result);
  225.         return(result);   }
  226.     if ( (adjsign < 0) && (opsign > 0) )
  227.        { *quadrant = 2;    fpchs(result,result);
  228.         return(result);   }
  229.     if ( (adjsign < 0) && (opsign < 0) )
  230.        { *quadrant = 3;    return (result);   }
  231. } /* arctan2 */
  232.  
  233. /*  CLOGS.C       */
  234.  
  235. char *pi(result)    char *result;    {
  236.     char *fpasg();
  237.     return (fpasg(result,PI) );
  238. } /* pi */
  239.  
  240. char *expe(result,xin)
  241.  /* computes the base of the natural log "e" raised to the "x'th"
  242.     power.  Checks are made for out of range values and result is
  243.     defaulted to 0, 1, or a large number as appropriate.  There are
  244.     no error flags.  The arguments are floating point character
  245.     arrays char result[5], x[5]; in calling program.  Return is
  246.     a pointer to result, and "e to the x" stored in result.
  247.  */
  248. char *result, *xin ;    {
  249.     char *one, *coef[7], x[5] ;
  250.     char  *fpmult(), *fpasg(), *fpdiv(), *fpchs();
  251.     int signx, index, bigexp, smallexp, zeroin;
  252.     int exprange();
  253.  
  254.     bigexp = smallexp = zeroin = 0;    one = ONE ;
  255.  
  256. /* preserve arg before transforms */
  257.     fpasg (x, xin) ;
  258.  
  259.     coef[0] = EXPC0 ;    coef[1] = EXPC1 ;
  260.     coef[2] = EXPC2 ;    coef[3] = EXPC3 ;
  261.     coef[4] = EXPC4 ;    coef[5] = EXPC5 ;
  262.     coef[6] = EXPC6 ;
  263.  
  264.  /* check for sign */
  265.     signx = 0 ;
  266.     if (x[3] < 128)  signx = 1; /* positive */
  267.     else fpchs(x,x) ;
  268.  
  269.    /* check for zero and very small numbers */
  270.     if ( ((127 < x[4]) && (x[4] < 226)) 
  271.     || ( (x[4]==0) && (x[3]==0) && (x[2]==0) 
  272.         && (x[1]==0) && (x[0]==0) ) )
  273.         zeroin = 1;
  274.  
  275.    /* check for very small exponent */
  276.     if ( fpcomp(x,MEGHTY6) < 0 )
  277.         smallexp = 1;
  278.  
  279.   /*  check for very large exponent */
  280.     if ( fpcomp(x,EGHTY6) > 0 )
  281.         bigexp = 1;
  282.  
  283.   /*  now if small number or zero, result is one */
  284.   /*  now if big number and positive, result is large number */
  285.   /*  now if big number and negative, result is zero */
  286.  
  287.     if (zeroin)    return (fpasg(result,one) );
  288.     if (smallexp)    return (fpasg(result,ZERO) );
  289.     if (bigexp)    return (fpasg(result,LARGE) );
  290.  
  291.  /*  all exceptions taken care of, so evaluate rest  */
  292.         fpasg(result,one);
  293.     /* fast loop */
  294.         for (index = 5, fpasg (result, coef[6]); 0<=index ;
  295.         --index)
  296.         fpadd (result, coef[index],
  297.             fpmult (result, result, x) ) ;
  298.  
  299.   /* now do the square square */
  300.     fpmult(result,result,result);
  301.     fpmult(result,result,result);
  302.  
  303.   /* now treat sign appropriately */
  304.     if (signx)    return (result);
  305.     else        return fpdiv (result, one, result) ;
  306. } /* expe */
  307.  
  308. char *exp10(result,xin)
  309. /* similar to expe, except result returned is 10 raised to the
  310.  xth power:   the antilogarithm to base 10  */
  311. char *result, *xin;    {
  312.     char *one ;
  313.     char *coef[7], tenfac[5], x[5] ;
  314.     int index, bigexp, smallexp, signx, tenpower;
  315.     int exprange();
  316.     bigexp = smallexp = 0;    one =  ONE ;
  317.  
  318.     coef[0] = ONE ;
  319.     coef[1] = E10C1 ;    coef[2] = E10C2 ;
  320.     coef[3] = E10C3 ;    coef[4] = E10C4 ;
  321.     coef[5] = E10C5 ;    coef[6] = E10C6 ;
  322.  
  323.  /* check for sign */
  324.     signx = 0 ;    fpasg (x, xin) ;
  325.     if (x[3] < 128)    /* positive */   signx = 1;
  326.     else        /* negative */   fpchs(x,x);
  327.  
  328.   /* check for very small or large numbers, check by exponent size */
  329.   /* check for zero or small */
  330.     if ( ((127 < x[4]) && (x[4] < 226)) 
  331.     || ( (x[4]==0) && (x[3]==0) && (x[2]==0) 
  332.         && (x[1]==0) && (x[0]==0) ) )
  333.         smallexp = 1;
  334.    /* check for big number */
  335.     if ( fpcomp(x,THTY8) > 0)
  336.         bigexp = 1;
  337.  
  338.  /* if value is small or zero, return 1 as with expe */
  339.  /* if value is large and positive, return a large number */
  340.  /* if value is large and negative, return zero */
  341.     if (smallexp)        return (fpasg(result,one) );
  342.     if (bigexp && signx)    return (fpasg(result,LARGE) );
  343.     if (bigexp && !signx)    return (fpasg(result,ZERO) );
  344.  
  345.  /* now reduce range of x to between zero and one */
  346.     tenpower = ftoit(x);    itof(tenfac,tenpower);
  347.     fpsub(x,x,tenfac);    fpasg(tenfac,one);
  348.     while (tenpower--)
  349.         fpmult(tenfac,tenfac,TEN);
  350.  
  351.  /* now evaluate series, fast loop */
  352.     for (fpasg (result, coef[6]), index = 5 ; 0 <= index ;
  353.         --index)
  354.         fpadd (result, coef[index],
  355.             fpmult (result, result, x) ) ;
  356.  
  357.  /* now square result (note error in referenced article) */
  358.     fpmult(result,result,result);
  359.  
  360.  /* now check sign and make proper return */
  361.     fpmult(result,result,tenfac);  /* scale back up */
  362.     if (signx)    return (result);
  363.     else        return ( fpdiv(result,one,result) );
  364. } /* exp10 */
  365.  
  366. char *log10 (result, sign, xin)
  367.  /* computes briggsian logarithm of x which is a char[5]
  368.     floating point number.  Return is logarithm in result[5],
  369.     and sign pointed to by sign.  The logarithm is taken
  370.     of the magnitude, and sign information preserved
  371.     as required by sign. */
  372. char *result, *xin ;    int *sign ;    {
  373.     char *zero, *ten, *one, *thty8, *sqrtten, x[5] ;
  374.     char gamma[5], gamnum[5], gamden[5], *coef[5] ;
  375.     char *half, intres[5] ;
  376.     int tenpower, index, bigexp, smallexp, signx ;
  377.     int exprange() ;
  378.  
  379.     bigexp = smallexp = 0 ;
  380.     zero = ZERO ;        half = HALF ;    one = ONE ;
  381.     sqrtten = SQRTTEN ;    ten = TEN ;    thty8 = THTY8 ;
  382.  
  383.     coef[0] = L10C0 ;    coef[1] = L10C1 ;
  384.     coef[2] = L10C2 ;    coef[3] = L10C3 ;
  385.     coef[4] = L10C4 ;
  386.  
  387.  /*  preserve input variable */
  388.     fpasg (x, xin) ;
  389.  
  390.  /* check for sign */
  391.     signx = -1 ;
  392.     if (x[3] < 128)   /* positive */   signx = 1 ;
  393.     else     /* negative */           fpchs (x, x) ;
  394.     *sign = signx ;
  395.  
  396.   /* check for very small or large numbers, check by exponent size */
  397.   /* check for zero or small */
  398.     if ( ( (127 < x[4]) && (x[4] < 209) ) 
  399.     || ( (x[4]==0) && (x[3]==0) && (x[2]==0) 
  400.         && (x[1]==0) && (x[0]==0) ) )
  401.         smallexp = 1 ;
  402.    /* check for big number */
  403.     if ( (47 < x[4]) && (x[4] < 128) )
  404.         bigexp = 1 ;
  405.  
  406.  /* if very small, return - a large number
  407.     if very large, return + a large number  */
  408.     if ( smallexp )    return ( fpchs (result, thty8) ) ;
  409.     if ( bigexp )    return ( fpasg (result, thty8) ) ;
  410.  
  411.   /*  bring into range 1 <= x < 10 */
  412.     tenpower = 0 ;
  413.     while ( fpcomp (x, ten) >= 0 )
  414.         { tenpower++ ;    fpdiv (x, x, ten) ; }
  415.     while ( fpcomp (x, one) < 0 )
  416.         { tenpower-- ;    fpmult (x, x, ten) ; }
  417.  
  418.   /* if exactly one, no need to evaluate */
  419.     fpsub (gamnum, x, one) ;
  420.     if ( ( (127 < gamnum[4]) && (gamnum[4] < 209) ) 
  421.     || ( (gamnum[0]==0) && (gamnum[1]==0) && 
  422.         (gamnum[2] == 0) && (gamnum[3] == 0) ) )
  423.         return ( itof (result, tenpower) ) ;
  424.  /* compute gamma for series  */
  425.  
  426.     fpsub (gamnum, x, sqrtten) ;
  427.   /* check for size of numerator */
  428.     if ( ( (127 < gamnum[4]) && (gamnum[4] < 209) ) 
  429.     || ( (gamnum[0]==0) && (gamnum[1]==0) 
  430.         && (gamnum[2] == 0) && (gamnum[3] == 0) ) )
  431.         { itof (result, tenpower) ;
  432.         return ( fpadd (result, result, half) ) ; }
  433.     fpadd (gamden, x, sqrtten) ;
  434.     fpdiv (gamma, gamnum, gamden) ;
  435.  
  436.  /* set up for series (use gamnum as gamma squared) */
  437.     fpmult (gamnum, gamma, gamma) ;
  438.  
  439.  /* do series evaluation */
  440.     for (fpasg (result, coef[4]), index = 3 ; 0 <= index ;
  441.         --index)
  442.         fpadd (result, coef[index],
  443.             fpmult (result, result, gamnum) ) ;
  444.     fpadd (result, half, 
  445.         fpmult (result, result, gamma) ) ;
  446.  
  447.  /* do correction for range reduction */
  448.     if ( tenpower != 0 )
  449.         fpadd (result, result, 
  450.             itof (intres, tenpower) ) ;
  451.  
  452.  /* return */
  453.     return (result) ;
  454. } /* log10 */
  455.  
  456. int exprange(x)
  457.  /* The input argument is a floating point value from BDS C 
  458. which consists of an array of 5 character data.  The function 
  459. returns a 1 if the exponent is in the range of - 47 to + 47.  
  460. Outside this range a value of 0 (false) is returned.  This is 
  461. a range of ten to plus or minus 14 power */
  462. char *x; { 
  463.   if ( ((x[4]<128) && (x[4]>47) ) 
  464.   || ((x[4]>127) && (x[4] < 209) ) )
  465.     return (0);
  466.   else return (1);
  467. } /* exprange */
  468.  
  469. dd (gamden, x, sqrtten) ;
  470.     fpdiv (gamma, gamnum, gamden) ;
  471.