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