home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / X / XcmsTrig.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  14.7 KB  |  592 lines

  1. /* $XConsortium: XcmsTrig.c,v 1.4 91/11/05 11:02:20 rws Exp $" */
  2.  
  3. /*
  4.  * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
  5.  *     All Rights Reserved
  6.  * 
  7.  * This file is a component of an X Window System-specific implementation
  8.  * of Xcms based on the TekColor Color Management System.  Permission is
  9.  * hereby granted to use, copy, modify, sell, and otherwise distribute this
  10.  * software and its documentation for any purpose and without fee, provided
  11.  * that this copyright, permission, and disclaimer notice is reproduced in
  12.  * all copies of this software and in supporting documentation.  TekColor
  13.  * is a trademark of Tektronix, Inc.
  14.  * 
  15.  * Tektronix makes no representation about the suitability of this software
  16.  * for any purpose.  It is provided "as is" and with all faults.
  17.  * 
  18.  * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
  19.  * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  20.  * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
  21.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  22.  * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
  23.  * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  24.  * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
  25.  */
  26.  
  27. /*
  28.  *    It should be pointed out that for simplicity's sake, the
  29.  *    environment parameters are defined as floating point constants,
  30.  *    rather than octal or hexadecimal initializations of allocated
  31.  *    storage areas.  This means that the range of allowed numbers
  32.  *    may not exactly match the hardware's capabilities.  For example,
  33.  *    if the maximum positive double precision floating point number
  34.  *    is EXACTLY 1.11...E100 and the constant "MAXDOUBLE is
  35.  *    defined to be 1.11E100 then the numbers between 1.11E100 and
  36.  *    1.11...E100 are considered to be undefined.  For most
  37.  *    applications, this will cause no problems.
  38.  *
  39.  *    An alternate method is to allocate a global static "double" variable,
  40.  *    say "maxdouble", and use a union declaration and initialization
  41.  *    to initialize it with the proper bits for the EXACT maximum value.
  42.  *    This was not done because the only compilers available to the
  43.  *    author did not fully support union initialization features.
  44.  *
  45.  */
  46.  
  47. /*
  48.  *    EXTERNS
  49.  */
  50. extern double _XcmsSquareRoot();
  51.  
  52. /*
  53.  *    FORWARD DECLARATIONS
  54.  */
  55. double _XcmsCosine();
  56. static double _XcmsModulo();
  57. static double _XcmsModuloF();
  58. static double _XcmsPolynomial();
  59. double _XcmsSine();
  60. double _XcmsArcTangent();
  61.  
  62. /*
  63.  *    DEFINES
  64.  */
  65.  
  66. #define XCMS_MAXERROR           0.000001
  67. #define XCMS_MAXITER           10000
  68. #define XCMS_PI               3.14159265358979323846264338327950
  69. #define XCMS_TWOPI         6.28318530717958620
  70. #define XCMS_HALFPI        1.57079632679489660
  71. #define XCMS_FOURTHPI        0.785398163397448280
  72. #define XCMS_SIXTHPI        0.523598775598298820
  73. #define XCMS_RADIANS(d)        ((d) * XCMS_PI / 180.0)
  74. #define XCMS_DEGREES(r)        ((r) * 180.0 / XCMS_PI)
  75. #define XCMS_X6_UNDERFLOWS    (4.209340e-52)    /* X**6 almost underflows */
  76. #define XCMS_X16_UNDERFLOWS    (5.421010e-20)    /* X**16 almost underflows*/
  77. #define XCMS_CHAR_BIT        8
  78. #define XCMS_LONG_MAX        0x7FFFFFFF
  79. #define XCMS_DEXPLEN        11
  80. #define XCMS_NBITS(type)    (XCMS_CHAR_BIT * (int)sizeof(type))
  81. #define XCMS_FABS(x)        ((x) < 0.0 ? -(x) : (x))
  82.  
  83. /* XCMS_DMAXPOWTWO - largest power of two exactly representable as a double */
  84. #define XCMS_DMAXPOWTWO    ((double)(XCMS_LONG_MAX) * \
  85.         (1L << (XCMS_NBITS(double)-XCMS_DEXPLEN) - XCMS_NBITS(long) + 1))
  86.  
  87. /*
  88.  *    LOCAL VARIABLES
  89.  */
  90.  
  91. static double cos_pcoeffs[] = {
  92.     0.12905394659037374438e7,
  93.    -0.37456703915723204710e6,
  94.     0.13432300986539084285e5,
  95.    -0.11231450823340933092e3
  96. };
  97.  
  98. static double cos_qcoeffs[] = {
  99.     0.12905394659037373590e7,
  100.     0.23467773107245835052e5,
  101.     0.20969518196726306286e3,
  102.     1.0
  103. };
  104.  
  105. static double sin_pcoeffs[] = {
  106.     0.20664343336995858240e7,
  107.    -0.18160398797407332550e6,
  108.     0.35999306949636188317e4,
  109.    -0.20107483294588615719e2
  110. };
  111.  
  112. static double sin_qcoeffs[] = {
  113.     0.26310659102647698963e7,
  114.     0.39270242774649000308e5,
  115.     0.27811919481083844087e3,
  116.     1.0
  117. };
  118.  
  119. /*
  120.  *
  121.  *  FUNCTION
  122.  *
  123.  *    _XcmsCosine   double precision cosine
  124.  *
  125.  *  KEY WORDS
  126.  *
  127.  *    cos
  128.  *    machine independent routines
  129.  *    trigonometric functions
  130.  *    math libraries
  131.  *
  132.  *  DESCRIPTION
  133.  *
  134.  *    Returns double precision cosine of double precision
  135.  *    floating point argument.
  136.  *
  137.  *  USAGE
  138.  *
  139.  *    double _XcmsCosine (x)
  140.  *    double x;
  141.  *
  142.  *  REFERENCES
  143.  *
  144.  *    Computer Approximations, J.F. Hart et al, John Wiley & Sons,
  145.  *    1968, pp. 112-120.
  146.  *
  147.  *  RESTRICTIONS
  148.  *
  149.  *    The sin and cos routines are interactive in the sense that
  150.  *    in the process of reducing the argument to the range -PI/4
  151.  *    to PI/4, each may call the other.  Ultimately one or the
  152.  *    other uses a polynomial approximation on the reduced
  153.  *    argument.  The sin approximation has a maximum relative error
  154.  *    of 10**(-17.59) and the cos approximation has a maximum
  155.  *    relative error of 10**(-16.18).
  156.  *
  157.  *    These error bounds assume exact arithmetic
  158.  *    in the polynomial evaluation.  Additional rounding and
  159.  *    truncation errors may occur as the argument is reduced
  160.  *    to the range over which the polynomial approximation
  161.  *    is valid, and as the polynomial is evaluated using
  162.  *    finite-precision arithmetic.
  163.  *    
  164.  *  PROGRAMMER
  165.  *
  166.  *    Fred Fish
  167.  *
  168.  *  INTERNALS
  169.  *
  170.  *    Computes cos(x) from:
  171.  *
  172.  *        (1)    Reduce argument x to range -PI to PI.
  173.  *
  174.  *        (2)    If x > PI/2 then call cos recursively
  175.  *            using relation cos(x) = -cos(x - PI).
  176.  *
  177.  *        (3)    If x < -PI/2 then call cos recursively
  178.  *            using relation cos(x) = -cos(x + PI).
  179.  *
  180.  *        (4)    If x > PI/4 then call sin using
  181.  *            relation cos(x) = sin(PI/2 - x).
  182.  *
  183.  *        (5)    If x < -PI/4 then call cos using
  184.  *            relation cos(x) = sin(PI/2 + x).
  185.  *
  186.  *        (6)    If x would cause underflow in approx
  187.  *            evaluation arithmetic then return
  188.  *            sqrt(1.0 - x**2).
  189.  *
  190.  *        (7)    By now x has been reduced to range
  191.  *            -PI/4 to PI/4 and the approximation
  192.  *            from HART pg. 119 can be used:
  193.  *
  194.  *            cos(x) = ( p(y) / q(y) )
  195.  *            Where:
  196.  *
  197.  *            y    =    x * (4/PI)
  198.  *
  199.  *            p(y) =  SUM [ Pj * (y**(2*j)) ]
  200.  *            over j = {0,1,2,3}
  201.  *
  202.  *            q(y) =  SUM [ Qj * (y**(2*j)) ]
  203.  *            over j = {0,1,2,3}
  204.  *
  205.  *            P0   =    0.12905394659037374438571854e+7
  206.  *            P1   =    -0.3745670391572320471032359e+6
  207.  *            P2   =    0.134323009865390842853673e+5
  208.  *            P3   =    -0.112314508233409330923e+3
  209.  *            Q0   =    0.12905394659037373590295914e+7
  210.  *            Q1   =    0.234677731072458350524124e+5
  211.  *            Q2   =    0.2096951819672630628621e+3
  212.  *            Q3   =    1.0000...
  213.  *            (coefficients from HART table #3843 pg 244)
  214.  *
  215.  *
  216.  *    **** NOTE ****    The range reduction relations used in
  217.  *    this routine depend on the final approximation being valid
  218.  *    over the negative argument range in addition to the positive
  219.  *    argument range.  The particular approximation chosen from
  220.  *    HART satisfies this requirement, although not explicitly
  221.  *    stated in the text.  This may not be true of other
  222.  *    approximations given in the reference.
  223.  *            
  224.  */
  225.  
  226. double _XcmsCosine (x)
  227. double x;
  228. {
  229.     auto double y;
  230.     auto double yt2;
  231.     double retval;
  232.  
  233.     if (x < -XCMS_PI || x > XCMS_PI) {
  234.     x = _XcmsModulo (x, XCMS_TWOPI);
  235.         if (x > XCMS_PI) {
  236.         x = x - XCMS_TWOPI;
  237.         } else if (x < -XCMS_PI) {
  238.         x = x + XCMS_TWOPI;
  239.         }
  240.     }
  241.     if (x > XCMS_HALFPI) {
  242.     retval = -(_XcmsCosine (x - XCMS_PI));
  243.     } else if (x < -XCMS_HALFPI) {
  244.     retval = -(_XcmsCosine (x + XCMS_PI));
  245.     } else if (x > XCMS_FOURTHPI) {
  246.     retval = _XcmsSine (XCMS_HALFPI - x);
  247.     } else if (x < -XCMS_FOURTHPI) {
  248.     retval = _XcmsSine (XCMS_HALFPI + x);
  249.     } else if (x < XCMS_X6_UNDERFLOWS && x > -XCMS_X6_UNDERFLOWS) {
  250.     retval = _XcmsSquareRoot (1.0 - (x * x));
  251.     } else {
  252.     y = x / XCMS_FOURTHPI;
  253.     yt2 = y * y;
  254.     retval = _XcmsPolynomial (3, cos_pcoeffs, yt2) / _XcmsPolynomial (3, cos_qcoeffs, yt2);
  255.     }
  256.     return (retval);
  257. }
  258.  
  259.  
  260. /*
  261.  *  FUNCTION
  262.  *
  263.  *    _XcmsModulo   double precision modulo
  264.  *
  265.  *  KEY WORDS
  266.  *
  267.  *    _XcmsModulo
  268.  *    machine independent routines
  269.  *    math libraries
  270.  *
  271.  *  DESCRIPTION
  272.  *
  273.  *    Returns double precision modulo of two double
  274.  *    precision arguments.
  275.  *
  276.  *  USAGE
  277.  *
  278.  *    double _XcmsModulo (value, base)
  279.  *    double value;
  280.  *    double base;
  281.  *
  282.  *  PROGRAMMER
  283.  *
  284.  *    Fred Fish
  285.  *
  286.  */
  287. static double _XcmsModulo (value, base)
  288. double value;
  289. double base;
  290. {
  291.     auto double intpart;
  292.  
  293.     value /= base;
  294.     value = _XcmsModuloF (value, &intpart);
  295.     value *= base;
  296.     return(value);
  297. }
  298.  
  299.  
  300. /*
  301.  * frac = (double) _XcmsModuloF(double val, double *dp)
  302.  *    return fractional part of 'val'
  303.  *    set *dp to integer part of 'val'
  304.  *
  305.  * Note  -> only compiled for the CA or KA.  For the KB/MC,
  306.  * "math.c" instantiates a copy of the inline function
  307.  * defined in "math.h".
  308.  */
  309. static double
  310. _XcmsModuloF(val, dp)
  311. double val;
  312. register double *dp;
  313. {
  314.     register double abs;
  315.     register double ip;
  316.  
  317.     /* should check for illegal values here - nan, inf, etc */
  318.     abs = XCMS_FABS(val);
  319.     if (abs >= XCMS_DMAXPOWTWO) {
  320.         ip = val;
  321.     } else {
  322.         ip = abs + XCMS_DMAXPOWTWO;    /* dump fraction */
  323.         ip -= XCMS_DMAXPOWTWO;    /* restore w/o frac */
  324.         if (ip > abs)        /* if it rounds up */
  325.             ip -= 1.0;    /* fix it */
  326.         ip = XCMS_FABS(ip);
  327.     }
  328.     *dp = ip;
  329.     return (val - ip); /* signed fractional part */
  330. }
  331.  
  332.  
  333. /*
  334.  *  FUNCTION
  335.  *
  336.  *    _XcmsPolynomial   double precision polynomial evaluation
  337.  *
  338.  *  KEY WORDS
  339.  *
  340.  *    poly
  341.  *    machine independent routines
  342.  *    math libraries
  343.  *
  344.  *  DESCRIPTION
  345.  *
  346.  *    Evaluates a polynomial and returns double precision
  347.  *    result.  Is passed a the order of the polynomial,
  348.  *    a pointer to an array of double precision polynomial
  349.  *    coefficients (in ascending order), and the independent
  350.  *    variable.
  351.  *
  352.  *  USAGE
  353.  *
  354.  *    double _XcmsPolynomial (order, coeffs, x)
  355.  *    int order;
  356.  *    double *coeffs;
  357.  *    double x;
  358.  *
  359.  *  PROGRAMMER
  360.  *
  361.  *    Fred Fish
  362.  *
  363.  *  INTERNALS
  364.  *
  365.  *    Evalates the polynomial using recursion and the form:
  366.  *
  367.  *        P(x) = P0 + x(P1 + x(P2 +...x(Pn)))
  368.  *
  369.  */
  370.  
  371. static double _XcmsPolynomial (order, coeffs, x)
  372. register int order;
  373. double *coeffs;
  374. double x;
  375. {
  376.     auto double rtn_value;
  377.  
  378. #if 0
  379.     auto double curr_coeff;
  380.     if (order <= 0) {
  381.     rtn_value = *coeffs;
  382.     } else {
  383.     curr_coeff = *coeffs;    /* Bug in Unisoft's compiler.  Does not */
  384.     coeffs++;        /* generate good code for *coeffs++ */
  385.     rtn_value = curr_coeff + x * _XcmsPolynomial (--order, coeffs, x);
  386.     }
  387. #else /* ++jrb -- removed tail recursion */
  388.     coeffs += order;
  389.     rtn_value = *coeffs--;
  390.     while(order-- > 0)
  391.     rtn_value = *coeffs-- + (x * rtn_value);
  392. #endif
  393.  
  394.     return(rtn_value);
  395. }
  396.  
  397.  
  398. /*
  399.  *  FUNCTION
  400.  *
  401.  *    _XcmsSine    double precision sine
  402.  *
  403.  *  KEY WORDS
  404.  *
  405.  *    sin
  406.  *    machine independent routines
  407.  *    trigonometric functions
  408.  *    math libraries
  409.  *
  410.  *  DESCRIPTION
  411.  *
  412.  *    Returns double precision sine of double precision
  413.  *    floating point argument.
  414.  *
  415.  *  USAGE
  416.  *
  417.  *    double _XcmsSine (x)
  418.  *    double x;
  419.  *
  420.  *  REFERENCES
  421.  *
  422.  *    Computer Approximations, J.F. Hart et al, John Wiley & Sons,
  423.  *    1968, pp. 112-120.
  424.  *
  425.  *  RESTRICTIONS
  426.  *
  427.  *    The sin and cos routines are interactive in the sense that
  428.  *    in the process of reducing the argument to the range -PI/4
  429.  *    to PI/4, each may call the other.  Ultimately one or the
  430.  *    other uses a polynomial approximation on the reduced
  431.  *    argument.  The sin approximation has a maximum relative error
  432.  *    of 10**(-17.59) and the cos approximation has a maximum
  433.  *    relative error of 10**(-16.18).
  434.  *
  435.  *    These error bounds assume exact arithmetic
  436.  *    in the polynomial evaluation.  Additional rounding and
  437.  *    truncation errors may occur as the argument is reduced
  438.  *    to the range over which the polynomial approximation
  439.  *    is valid, and as the polynomial is evaluated using
  440.  *    finite-precision arithmetic.
  441.  *    
  442.  *  PROGRAMMER
  443.  *
  444.  *    Fred Fish
  445.  *
  446.  *  INTERNALS
  447.  *
  448.  *    Computes sin(x) from:
  449.  *
  450.  *      (1)    Reduce argument x to range -PI to PI.
  451.  *
  452.  *      (2)    If x > PI/2 then call sin recursively
  453.  *        using relation sin(x) = -sin(x - PI).
  454.  *
  455.  *      (3)    If x < -PI/2 then call sin recursively
  456.  *        using relation sin(x) = -sin(x + PI).
  457.  *
  458.  *      (4)    If x > PI/4 then call cos using
  459.  *        relation sin(x) = cos(PI/2 - x).
  460.  *
  461.  *      (5)    If x < -PI/4 then call cos using
  462.  *        relation sin(x) = -cos(PI/2 + x).
  463.  *
  464.  *      (6)    If x is small enough that polynomial
  465.  *        evaluation would cause underflow
  466.  *        then return x, since sin(x)
  467.  *        approaches x as x approaches zero.
  468.  *
  469.  *      (7)    By now x has been reduced to range
  470.  *        -PI/4 to PI/4 and the approximation
  471.  *        from HART pg. 118 can be used:
  472.  *
  473.  *        sin(x) = y * ( p(y) / q(y) )
  474.  *        Where:
  475.  *
  476.  *        y    =  x * (4/PI)
  477.  *
  478.  *        p(y) =  SUM [ Pj * (y**(2*j)) ]
  479.  *        over j = {0,1,2,3}
  480.  *
  481.  *        q(y) =  SUM [ Qj * (y**(2*j)) ]
  482.  *        over j = {0,1,2,3}
  483.  *
  484.  *        P0   =  0.206643433369958582409167054e+7
  485.  *        P1   =  -0.18160398797407332550219213e+6
  486.  *        P2   =  0.359993069496361883172836e+4
  487.  *        P3   =  -0.2010748329458861571949e+2
  488.  *        Q0   =  0.263106591026476989637710307e+7
  489.  *        Q1   =  0.3927024277464900030883986e+5
  490.  *        Q2   =  0.27811919481083844087953e+3
  491.  *        Q3   =  1.0000...
  492.  *        (coefficients from HART table #3063 pg 234)
  493.  *
  494.  *
  495.  *    **** NOTE ****      The range reduction relations used in
  496.  *    this routine depend on the final approximation being valid
  497.  *    over the negative argument range in addition to the positive
  498.  *    argument range.  The particular approximation chosen from
  499.  *    HART satisfies this requirement, although not explicitly
  500.  *    stated in the text.  This may not be true of other
  501.  *    approximations given in the reference.
  502.  *            
  503.  */
  504.  
  505. double
  506. _XcmsSine (x)
  507. double x;
  508. {
  509.     double y;
  510.     double yt2;
  511.     double retval;
  512.  
  513.     if (x < -XCMS_PI || x > XCMS_PI) {
  514.     x = _XcmsModulo (x, XCMS_TWOPI);
  515.     if (x > XCMS_PI) {
  516.         x = x - XCMS_TWOPI;
  517.     } else if (x < -XCMS_PI) {
  518.         x = x + XCMS_TWOPI;
  519.     }
  520.     }
  521.     if (x > XCMS_HALFPI) {
  522.     retval = -(_XcmsSine (x - XCMS_PI));
  523.     } else if (x < -XCMS_HALFPI) {
  524.     retval = -(_XcmsSine (x + XCMS_PI));
  525.     } else if (x > XCMS_FOURTHPI) {
  526.     retval = _XcmsCosine (XCMS_HALFPI - x);
  527.     } else if (x < -XCMS_FOURTHPI) {
  528.     retval = -(_XcmsCosine (XCMS_HALFPI + x));
  529.     } else if (x < XCMS_X6_UNDERFLOWS && x > -XCMS_X6_UNDERFLOWS) {
  530.     retval = x;
  531.     } else {
  532.     y = x / XCMS_FOURTHPI;
  533.     yt2 = y * y;
  534.     retval = y * (_XcmsPolynomial (3, sin_pcoeffs, yt2) / _XcmsPolynomial(3, sin_qcoeffs, yt2));
  535.     }
  536.     return(retval);
  537. }
  538.  
  539.  
  540. /*
  541.  *    NAME
  542.  *        _XcmsArcTangent
  543.  *
  544.  *    SYNOPSIS
  545.  */
  546. double
  547. _XcmsArcTangent(x)
  548.     double x;
  549. /*
  550.  *    DESCRIPTION
  551.  *        Computes the arctangent.
  552.  *        This is an implementation of the Gauss algorithm as
  553.  *        described in:
  554.  *            Forman S. Acton, Numerical Methods That Work,
  555.  *            New York, NY, Harper & Row, 1970.
  556.  *
  557.  *    RETURNS
  558.  *        Returns the arctangent 
  559.  */
  560. {
  561.     double ai, a1, bi, b1, l, d;
  562.     double maxerror;
  563.     int i;
  564.  
  565.     if (x == 0.0)  {
  566.     return (0.0);
  567.     }
  568.     if (x < 1.0) {
  569.     maxerror = x * XCMS_MAXERROR;
  570.     } else {
  571.     maxerror = XCMS_MAXERROR;
  572.     }
  573.     ai = _XcmsSquareRoot( 1.0 / (1.0 + (x * x)) );
  574.     bi = 1.0;
  575.     for (i = 0; i < XCMS_MAXITER; i++) {
  576.     a1 = (ai + bi) / 2.0;
  577.     b1 = _XcmsSquareRoot((a1 * bi));
  578.     if (a1 == b1)
  579.         break;
  580.     d = XCMS_FABS(a1 - b1);
  581.     if (d < maxerror)
  582.         break;
  583.     ai = a1;
  584.     bi = b1;
  585.     }
  586.  
  587.     l = ((a1 > b1) ? b1 : a1);
  588.  
  589.     a1 = _XcmsSquareRoot(1 + (x * x));
  590.     return (x / (a1 * l));
  591. }
  592.