Headers and library sources from all versions of Lightspeed C and THINK C
at heads/lightspeed_c-3.02 612 lines 7.8 kB view raw
1 2/* 3 4 Math library for LightspeedC 5 6 (C) Copyright 1986 THINK Technologies. All rights reserved. 7 8 For details, refer to Harbison & Steele's "C: A Reference Manual", 9 Chapter 11. 10 11 Only one version of each function is defined by this library. 12 Whether error checking is done is determined by how this file 13 is compiled. Error checking is ENABLED when the following 14 #define is COMMENTED OUT. 15 16*/ 17 18/*#define _NOERRORCHECK_*/ 19#include "math.h" 20#include "sane.h" 21 22/* useful constants */ 23static double Zero = 0.0; 24static double One = 1.0; 25static double Two = 2.0; 26static double MinusOne = -1.0; 27static double MinusTwo = -2.0; 28static double PointFive = 0.5; 29static double PointTwoFive = 0.25; 30static double Pi = PI; 31static double Pi2 = PI2; 32static double Log2Ten = 3.321928094887362348; 33 34static short _Max[] = { 0x7FFE, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF }; 35static short _MinusMax[] = { 0xFFFE, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF }; 36#define Max (* (double *) _Max) 37#define MinusMax (* (double *) _MinusMax) 38 39/* seed for pseudo-random number generator */ 40static unsigned long seed = 1; 41 42 43/* environment word masks */ 44#define ROUND 0x6000 45#define ROUND_UP 0x2000 46#define ROUND_DOWN 0x4000 47#define ERROR 0x0F00 48 49 50/* ---------- error checking ---------- */ 51 52#ifdef _ERRORCHECK_ 53 54#define DomainCheck(test, result) if (test) { \ 55 errno = EDOM; \ 56 return(result); \ 57 } 58#define RangeCheck(target) if (GetState() & ERROR) { \ 59 errno = ERANGE; \ 60 target = Max; \ 61 } 62 63#else _ERRORCHECK_ 64 65#define ClearExceptions() 66#define DomainCheck(test, result) 67#define RangeCheck(target) 68 69#endif _ERRORCHECK_ 70 71/* ---------- environment ---------- */ 72 73 74/* 75 * GetState - query environment word 76 * 77 */ 78 79static 80GetState() 81{ 82 int state; 83 84 GetEnvironment(&state); 85 return(state); 86} 87 88 89/* 90 * SetState - define environment word 91 * 92 */ 93 94static 95SetState(state) 96{ 97 SetEnvironment(&state); 98} 99 100 101/* 102 * ClearExceptions - clear error conditions 103 * 104 * This must be called if RangeCheck is to be used. 105 * 106 */ 107 108#ifdef _ERRORCHECK_ 109static 110ClearExceptions() 111{ 112 int state; 113 114 GetEnvironment(&state); 115 state &= ~ERROR; 116 SetEnvironment(&state); 117} 118#endif _ERRORCHECK_ 119 120 121/* 122 * SetRound - define rounding direction 123 * 124 * The previous environment word is returned. The rounding direction can 125 * be restored by passing this value to SetState. 126 * 127 */ 128 129static 130SetRound(direction) 131{ 132 int state; 133 134 GetEnvironment(&state); 135 SetState((state & ~ROUND) | direction); 136 return(state); 137} 138 139 140/* 141 * xfersign - transfer sign from one floating number to another 142 * 143 */ 144 145static 146xfersign(x, yp) 147double x, *yp; 148{ 149 asm { 150 movea.l yp,a0 151 bclr #7,(a0) 152 tst.w x 153 bpl.s @1 154 bset #7,(a0) 155@1 } 156} 157 158 159/* ---------- math functions (alphabetically) ---------- */ 160 161 162/* 163 * abs - absolute value of an integer 164 * 165 */ 166 167int abs(x) 168int x; 169{ 170 return(x < 0 ? -x : x); 171} 172 173 174/* 175 * acos - inverse circular cosine 176 * 177 */ 178 179double acos(x) 180double x; 181{ 182 DomainCheck(x > One || x < MinusOne, Zero); 183 if (x == MinusOne) 184 return(Pi); 185 return(Two * atan(sqrt((One - x) / (One + x)))); 186} 187 188 189/* 190 * asin - inverse circular sine 191 * 192 */ 193 194double asin(x) 195double x; 196{ 197 double y = fabs(x); 198 199 DomainCheck(y > One, Zero); 200 if (y == One) { 201 y = Pi2; 202 xfersign(x, &y); 203 return(y); 204 } 205 if (y > PointFive) { 206 y = One - y; 207 y = Two * y - y * y; 208 } 209 else 210 y = One - y * y; 211 return(atan(x / sqrt(y))); 212} 213 214 215/* 216 * atan - inverse circular tangent 217 * 218 */ 219 220double atan(x) 221double x; 222{ 223 elems68k(&x, FOATANX); 224 return(x); 225} 226 227 228/* 229 * atan2 - inverse circular tangent (y/x) 230 * 231 */ 232 233double atan2(y, x) 234double y, x; 235{ 236 double z; 237 238 if (x == 0) { 239 DomainCheck(y == 0, Zero); 240 z = Pi2; 241 } 242 else { 243 z = atan(fabs(y / x)); 244 if (x < 0) 245 z = Pi - z; 246 } 247 xfersign(y, &z); 248 return(z); 249} 250 251 252/* 253 * ceil - round up to an integer 254 * 255 */ 256 257double ceil(x) 258double x; 259{ 260 int state = SetRound(ROUND_UP); 261 fp68k(&x, FORTI); 262 SetState(state); 263 return(x); 264} 265 266 267/* 268 * cos - circular cosine 269 * 270 */ 271 272double cos(x) 273double x; 274{ 275 elems68k(&x, FOCOSX); 276 return(x); 277} 278 279 280/* 281 * cosh - hyperbolic cosine 282 * 283 */ 284 285double cosh(x) 286double x; 287{ 288 ClearExceptions(); 289 x = PointFive * exp(fabs(x)); 290 x += PointTwoFive / x; 291 RangeCheck(x); 292 return(x); 293} 294 295 296/* 297 * exp - exponential function 298 * 299 */ 300 301double exp(x) 302double x; 303{ 304 ClearExceptions(); 305 elems68k(&x, FOEXPX); 306 RangeCheck(x); 307 return(x); 308} 309 310 311/* 312 * fabs - absolute value of a floating number 313 * 314 */ 315 316double fabs(x) 317double x; 318{ 319 fp68k(&x, FOABS); 320 return(x); 321} 322 323 324/* 325 * floor - round down to an integer 326 * 327 */ 328 329double floor(x) 330double x; 331{ 332 int state = SetRound(ROUND_DOWN); 333 334 fp68k(&x, FORTI); 335 SetState(state); 336 return(x); 337} 338 339 340/* 341 * fmod - remainder function 342 * 343 * This computes a value z, with the same sign as x, such that for some 344 * integer k, k*y + z == x. 345 * 346 */ 347 348double fmod(x, y) 349double x, y; 350{ 351 double z = x; 352 353 fp68k(&y, FOABS); 354 fp68k(&y, &z, FOREM); 355 356 if (x > 0 && z < 0) 357 z += y; 358 else if (x < 0 && z > 0) 359 z -= y; 360 return(z); 361} 362 363 364/* 365 * frexp - split floating number into fraction/exponent 366 * 367 * This computes a value z, where 0.5 <= fabs(z) < 1.0, and an integer n such 368 * that z*(2^n) == x. 369 * 370 */ 371 372double frexp(x, nptr) 373double x; 374register int *nptr; 375{ 376 double y = fabs(x), z = Two; 377 378 if (y == 0) { 379 *nptr = 0; 380 return(Zero); 381 } 382 383 elems68k(&y, FOLOG2X); 384 385 y -= *nptr = y; 386 387 elems68k(&y, &z, FOPWRY); 388 389 if (z >= One) { 390 z *= PointFive; 391 ++*nptr; 392 } 393 else if (z < PointFive) { 394 z += z; 395 --*nptr; 396 } 397 xfersign(x, &z); 398 return(z); 399} 400 401 402/* 403 * labs - absolute value of a long integer 404 * 405 */ 406 407long labs(x) 408long x; 409{ 410 return(x < 0 ? -x : x); 411} 412 413 414/* 415 * ldexp - combine fraction/exponent into a floating number 416 * 417 */ 418 419double ldexp(x, n) 420double x; 421int n; 422{ 423 fp68k(&n, &x, FOSCALB); 424 return(x); 425} 426 427 428/* 429 * log - natural logarithm 430 * 431 */ 432 433double log(x) 434double x; 435{ 436 DomainCheck(x <= 0, MinusMax); 437 elems68k(&x, FOLNX); 438 return(x); 439} 440 441 442/* 443 * log10 - logarithm base 10 444 * 445 */ 446 447double log10(x) 448double x; 449{ 450 DomainCheck(x <= 0, MinusMax); 451 elems68k(&x, FOLOG2X); /* LOG2 is much faster than LN */ 452 return(x / Log2Ten); 453} 454 455 456/* 457 * modf - split a floating number into fraction/integer 458 * 459 */ 460 461double modf(x, nptr) 462double x; 463register double *nptr; 464{ 465 *nptr = x; 466 fp68k(nptr, FOTTI); 467 return(x - *nptr); 468} 469 470 471/* 472 * pow - power function (exponentiation) 473 * 474 */ 475 476double pow(x, y) 477double x, y; 478{ 479 int odd = 0; 480 double z; 481 482 ClearExceptions(); 483 if (x == 0) { 484 if (y <= 0) { 485#ifdef _ERRORCHECK_ 486 errno = EDOM; 487#endif 488 return (MinusMax); 489 } 490 return(Zero); 491 } 492 if (y == 0) 493 return(One); 494 if (x < 0) { 495 if (modf(y, &y)) { 496#ifdef _ERRORCHECK_ 497 errno = EDOM; 498#endif 499 return (MinusMax); 500 } 501 x = -x; 502 odd = fmod(y, Two); 503 } 504 elems68k(&y, &x, FOPWRY); 505 506 RangeCheck(x); 507 return(odd ? -x : x); 508} 509 510/* 511 * rand - pseudo-random number generator (ANSI C standard) 512 * 513 */ 514 515int rand() 516{ 517 seed = seed * 1103515245 + 12345; 518 asm { 519 move.w seed,d0 ; high word of long 520 andi.w #0x7FFF,d0 ; remove high bit 521 } 522} 523 524 525/* 526 * sin - circular sine 527 * 528 */ 529 530double sin(x) 531double x; 532{ 533 elems68k(&x, FOSINX); 534 return(x); 535} 536 537 538/* 539 * sinh - hyperbolic sine 540 * 541 */ 542 543double sinh(x) 544double x; 545{ 546 double y = fabs(x); 547 548 ClearExceptions(); 549 elems68k(&y, FOEXP1X); 550 y += y / (y + One); 551 y *= PointFive; 552 RangeCheck(y); 553 xfersign(x, &y); 554 return(y); 555} 556 557 558/* 559 * sqrt - square root 560 * 561 */ 562 563double sqrt(x) 564double x; 565{ 566 DomainCheck(x < 0, Zero); 567 fp68k(&x, FOSQRT); 568 return(x); 569} 570 571 572/* 573 * srand - seed pseudo-random number generator 574 * 575 */ 576 577void srand(n) 578unsigned n; 579{ 580 seed = n; 581} 582 583 584/* 585 * tan - circular tangent 586 * 587 */ 588 589double tan(x) 590double x; 591{ 592 ClearExceptions(); 593 elems68k(&x, FOTANX); 594 RangeCheck(x); 595 return(x); 596} 597 598 599/* 600 * tanh - hyperbolic tangent 601 * 602 */ 603 604double tanh(x) 605double x; 606{ 607 double y = MinusTwo * fabs(x); 608 elems68k(&y, FOEXP1X); 609 y = -y / (y + Two); 610 xfersign(x, &y); 611 return(y); 612}