Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

929 lines
22 KiB

  1. /***
  2. *fpexcept.c - floating point exception handling
  3. *
  4. * Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *Revision History:
  9. * 08-24-91 GDP written
  10. * 09-26-91 GDP changed DOMAIN error handling
  11. * 10-10-91 GDP use fp addition for propagating NaNs
  12. * 01-14-92 GDP IEEE exception support
  13. * 03-20-92 GDP major changes, reorganized code
  14. * 03-31-92 GDP new interface, use internal fp control functions
  15. * 07-16-93 SRW ALPHA Merge
  16. * 11-18-93 GJF Merged in NT SDK version. Cleaned up preprocessing
  17. * conditional: replaced #if _NTSUBSET_ with #ifdef
  18. * _NTSUBSET_, i386 with _M_IX86, MIPS with _M_MRX000,
  19. * _ALPHA_ with _M_ALPHA.
  20. * 09-01-94 SKS Change include file from <nt.h> to <windows.h>
  21. * 09-05-94 SKS Change another #ifdef i386 to #ifdef _M_IX86
  22. * 10-02-94 BWT PPC merge and change NTSUBSET includes to use nt.h
  23. * 02-19-95 BWT Define _KERNEL32_ before including windows.h for _NTSUBSET_
  24. * build (otherwise declspec(dllimport) will be on for
  25. * RaiseException)
  26. * 03-29-95 BWT Add casts to fix warnings.
  27. * 05-10-96 BWT POSIX fix
  28. * 06-21-00 GB Add OP_LOGB in _get_fname.
  29. *
  30. *******************************************************************************/
  31. #if defined(_NTSUBSET_) || defined (_POSIX_)
  32. #include <nt.h>
  33. #include <ntrtl.h>
  34. #include <nturtl.h>
  35. #define _KERNEL32_ // Don't Export RaiseException
  36. #endif // _NTSUBSET_
  37. #include <trans.h>
  38. #include <errno.h>
  39. #include <math.h>
  40. #include <windows.h>
  41. #ifdef _NTSUBSET_
  42. VOID
  43. WINAPI
  44. RaiseException(
  45. DWORD dwExceptionCode,
  46. DWORD dwExceptionFlags,
  47. DWORD nNumberOfArguments,
  48. CONST DWORD_PTR *lpArguments
  49. )
  50. {
  51. EXCEPTION_RECORD ExceptionRecord;
  52. ULONG n;
  53. PULONG_PTR s,d;
  54. ExceptionRecord.ExceptionCode = (DWORD)dwExceptionCode;
  55. ExceptionRecord.ExceptionFlags = dwExceptionFlags & EXCEPTION_NONCONTINUABLE;
  56. ExceptionRecord.ExceptionRecord = NULL;
  57. ExceptionRecord.ExceptionAddress = (PVOID)RaiseException;
  58. if ( ARGUMENT_PRESENT(lpArguments) ) {
  59. n = nNumberOfArguments;
  60. if ( n > EXCEPTION_MAXIMUM_PARAMETERS ) {
  61. n = EXCEPTION_MAXIMUM_PARAMETERS;
  62. }
  63. ExceptionRecord.NumberParameters = n;
  64. s = (PULONG_PTR)lpArguments;
  65. d = ExceptionRecord.ExceptionInformation;
  66. while(n--){
  67. *d++ = *s++;
  68. }
  69. }
  70. else {
  71. ExceptionRecord.NumberParameters = 0;
  72. }
  73. RtlRaiseException(&ExceptionRecord);
  74. }
  75. #endif // _NTSUBSET_
  76. //
  77. // copy a double without generating floating point instructions
  78. // (avoid invalid operation on x87)
  79. //
  80. #define COPY_DOUBLE(pdest, psrc) \
  81. ( *(unsigned int *)pdest = *(unsigned int *)psrc, \
  82. *((unsigned int *)pdest+1) = *((unsigned int *)psrc+1) )
  83. //
  84. // _matherr_flag is a communal variable. It is equal to zero
  85. // if the user has redefined matherr(). Otherwise it has a
  86. // non zero value. The default matherr routine does nothing
  87. // and returns 0.
  88. //
  89. int _matherr_flag;
  90. //
  91. // a routine for artificially setting the fp status bits in order
  92. // to signal a software generated masked fp exception.
  93. //
  94. extern void _set_statfp(uintptr_t);
  95. void _raise_exc(_FPIEEE_RECORD *prec,uintptr_t *pcw,
  96. int flags, int opcode, double *parg1, double *presult);
  97. double _umatherr(int type, unsigned int opcode,
  98. double arg1, double arg2, double presult,
  99. uintptr_t cw);
  100. static char *_get_fname(unsigned int opcode);
  101. /***
  102. * _handle_qnan1, _handle_qnan2 - handle quiet NaNs as function arguments
  103. *
  104. *Purpose:
  105. * Do all necessary work for handling the case where the argument
  106. * or one of the arguments of a floating point function is a quiet NaN
  107. *
  108. *Entry:
  109. * unsigned int opcode: The operation code of the fp function
  110. * double x: the fp function argument
  111. * double y: the fp function second argument (_handle_qnan2 only)
  112. * uintptr_t savedcw: the user's control word
  113. *
  114. *Exit:
  115. * restore the user's control word, and
  116. * return the suggested return value for the fp function
  117. *
  118. *Exceptions:
  119. *
  120. *******************************************************************************/
  121. double _handle_qnan1(unsigned int opcode,
  122. double x,
  123. uintptr_t savedcw)
  124. {
  125. if (! _matherr_flag) {
  126. //
  127. // QNaN arguments are treated as domain errors
  128. // invoke the user's matherr routine
  129. // _umatherr will take care of restoring the
  130. // user's control word
  131. //
  132. return _umatherr(_DOMAIN,opcode,x,0.0,x,savedcw);
  133. }
  134. else {
  135. errno = EDOM;
  136. _rstorfp(savedcw);
  137. return x;
  138. }
  139. }
  140. double _handle_qnan2(unsigned int opcode,
  141. double x,
  142. double y,
  143. uintptr_t savedcw)
  144. {
  145. double result;
  146. //
  147. // NaN propagation should be handled by the underlying fp h/w
  148. //
  149. result = x+y;
  150. if (! _matherr_flag) {
  151. return _umatherr(_DOMAIN,opcode,x,y,result,savedcw);
  152. }
  153. else {
  154. errno = EDOM;
  155. _rstorfp(savedcw);
  156. return result;
  157. }
  158. }
  159. /***
  160. * _except1 - exception handling shell for fp functions with one argument
  161. *
  162. *Purpose:
  163. *
  164. *Entry:
  165. * int flags: the exception flags
  166. * int opcode: the operation code of the fp function that faulted
  167. * double arg: the argument of the fp function
  168. * double result: default result
  169. * uintptr_t cw: user's fp control word
  170. *
  171. *Exit:
  172. * restore user's fp control word
  173. * and return the (possibly modified) result of the fp function
  174. *
  175. *Exceptions:
  176. *
  177. *******************************************************************************/
  178. double _except1(int flags,
  179. int opcode,
  180. double arg,
  181. double result,
  182. uintptr_t cw)
  183. {
  184. int type;
  185. if (_handle_exc(flags, &result, cw) == 0) {
  186. //
  187. // At this point _handle_exception has failed to deal
  188. // with the error
  189. // An IEEE exception should be raised
  190. //
  191. _FPIEEE_RECORD rec;
  192. // The rec structure will be filled in by _raise_exc,
  193. // except for the Operand2 information
  194. rec.Operand2.OperandValid = 0;
  195. _raise_exc(&rec, &cw, flags, opcode, &arg, &result);
  196. }
  197. //
  198. // At this point we have either the masked response of the
  199. // exception, or a value supplied by the user's IEEE exception
  200. // handler. The _matherr mechanism is supported for backward
  201. // compatibility.
  202. //
  203. type = _errcode(flags);
  204. // Inexact result fp exception does not have a matherr counterpart;
  205. // in that case type is 0.
  206. if (! _matherr_flag && type) {
  207. return _umatherr(type, opcode, arg, 0.0, result, cw);
  208. }
  209. else {
  210. _set_errno(type);
  211. }
  212. RETURN(cw,result);
  213. }
  214. /***
  215. * _except2 - exception handling shell for fp functions with two arguments
  216. *
  217. *Purpose:
  218. *
  219. *Entry:
  220. * int flags: the exception flags
  221. * int opcode: the operation code of the fp function that faulted
  222. * double arg1: the first argument of the fp function
  223. * double arg2: the second argument of the fp function
  224. * double result: default result
  225. * unsigned int cw: user's fp control word
  226. *
  227. *Exit:
  228. * restore user's fp control word
  229. * and return the (possibly modified) result of the fp function
  230. *
  231. *Exceptions:
  232. *
  233. *******************************************************************************/
  234. double _except2(int flags,
  235. int opcode,
  236. double arg1,
  237. double arg2,
  238. double result,
  239. uintptr_t cw)
  240. {
  241. int type;
  242. if (_handle_exc(flags, &result, cw) == 0) {
  243. //
  244. // trap should be taken
  245. //
  246. _FPIEEE_RECORD rec;
  247. //
  248. // fill in operand2 info. The rest of rec will be
  249. // filled in by _raise_exc
  250. //
  251. rec.Operand2.OperandValid = 1;
  252. rec.Operand2.Format = _FpFormatFp64;
  253. rec.Operand2.Value.Fp64Value = arg2;
  254. _raise_exc(&rec, &cw, flags, opcode, &arg1, &result);
  255. }
  256. type = _errcode(flags);
  257. if (! _matherr_flag && type) {
  258. return _umatherr(type, opcode, arg1, arg2, result, cw);
  259. }
  260. else {
  261. _set_errno(type);
  262. }
  263. RETURN(cw,result);
  264. }
  265. /***
  266. * _raise_exc - raise fp IEEE exception
  267. *
  268. *Purpose:
  269. * fill in an fp IEEE record struct and raise a fp exception
  270. *
  271. *
  272. *Entry / Exit:
  273. * IN _FPIEEE_RECORD prec pointer to an IEEE record
  274. * IN OUT unsigned int *pcw pointer to user's fp control word
  275. * IN int flags, exception flags
  276. * IN int opcode, fp operation code
  277. * IN double *parg1, pointer to first argument
  278. * IN double *presult) pointer to result
  279. *
  280. *Exceptions:
  281. *
  282. *******************************************************************************/
  283. void _raise_exc( _FPIEEE_RECORD *prec,
  284. uintptr_t *pcw,
  285. int flags,
  286. int opcode,
  287. double *parg1,
  288. double *presult)
  289. {
  290. DWORD exc_code;
  291. uintptr_t sw;
  292. //
  293. // reset all control bits
  294. //
  295. *(int *)&(prec->Cause) = 0;
  296. *(int *)&(prec->Enable) = 0;
  297. *(int *)&(prec->Status) = 0;
  298. //
  299. // Precision exception may only coincide with overflow
  300. // or underflow. If this is the case, overflow (or
  301. // underflow) take priority over precision exception.
  302. // The order of checks is from the least important
  303. // to the most important exception
  304. //
  305. if (flags & FP_P) {
  306. exc_code = (DWORD) STATUS_FLOAT_INEXACT_RESULT;
  307. prec->Cause.Inexact = 1;
  308. }
  309. if (flags & FP_U) {
  310. exc_code = (DWORD) STATUS_FLOAT_UNDERFLOW;
  311. prec->Cause.Underflow = 1;
  312. }
  313. if (flags & FP_O) {
  314. exc_code = (DWORD) STATUS_FLOAT_OVERFLOW;
  315. prec->Cause.Overflow = 1;
  316. }
  317. if (flags & FP_Z) {
  318. exc_code = (DWORD) STATUS_FLOAT_DIVIDE_BY_ZERO;
  319. prec->Cause.ZeroDivide = 1;
  320. }
  321. if (flags & FP_I) {
  322. exc_code = (DWORD) STATUS_FLOAT_INVALID_OPERATION;
  323. prec->Cause.InvalidOperation = 1;
  324. }
  325. //
  326. // Set exception enable bits
  327. //
  328. prec->Enable.InvalidOperation = (*pcw & IEM_INVALID) ? 0 : 1;
  329. prec->Enable.ZeroDivide = (*pcw & IEM_ZERODIVIDE) ? 0 : 1;
  330. prec->Enable.Overflow = (*pcw & IEM_OVERFLOW) ? 0 : 1;
  331. prec->Enable.Underflow = (*pcw & IEM_UNDERFLOW) ? 0 : 1;
  332. prec->Enable.Inexact = (*pcw & IEM_INEXACT) ? 0 : 1;
  333. //
  334. // Set status bits
  335. //
  336. sw = _statfp();
  337. if (sw & ISW_INVALID) {
  338. prec->Status.InvalidOperation = 1;
  339. }
  340. if (sw & ISW_ZERODIVIDE) {
  341. prec->Status.ZeroDivide = 1;
  342. }
  343. if (sw & ISW_OVERFLOW) {
  344. prec->Status.Overflow = 1;
  345. }
  346. if (sw & ISW_UNDERFLOW) {
  347. prec->Status.Underflow = 1;
  348. }
  349. if (sw & ISW_INEXACT) {
  350. prec->Status.Inexact = 1;
  351. }
  352. switch (*pcw & IMCW_RC) {
  353. case IRC_CHOP:
  354. prec->RoundingMode = _FpRoundChopped;
  355. break;
  356. case IRC_UP:
  357. prec->RoundingMode = _FpRoundPlusInfinity;
  358. break;
  359. case IRC_DOWN:
  360. prec->RoundingMode = _FpRoundMinusInfinity;
  361. break;
  362. case IRC_NEAR:
  363. prec->RoundingMode = _FpRoundNearest;
  364. break;
  365. }
  366. #ifdef _M_IX86
  367. switch (*pcw & IMCW_PC) {
  368. case IPC_64:
  369. prec->Precision = _FpPrecisionFull;
  370. break;
  371. case IPC_53:
  372. prec->Precision = _FpPrecision53;
  373. break;
  374. case IPC_24:
  375. prec->Precision = _FpPrecision24;
  376. break;
  377. }
  378. #endif
  379. #if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC)
  380. prec->Precision = _FpPrecision53;
  381. #endif
  382. prec->Operation = opcode;
  383. prec->Operand1.OperandValid = 1;
  384. prec->Operand1.Format = _FpFormatFp64;
  385. prec->Operand1.Value.Fp64Value = *parg1;
  386. prec->Result.OperandValid = 1;
  387. prec->Result.Format = _FpFormatFp64;
  388. prec->Result.Value.Fp64Value = *presult;
  389. //
  390. // By convention software exceptions use the first exception
  391. // parameter in order to pass a pointer to the _FPIEEE_RECORD
  392. // structure.
  393. //
  394. _clrfp();
  395. RaiseException(exc_code,0,1,(uintptr_t *)&prec);
  396. //
  397. // user's trap handler may have changed either the fp environment
  398. // or the result
  399. //
  400. //
  401. // Update exception mask
  402. //
  403. if (prec->Enable.InvalidOperation)
  404. (*pcw) &= ~IEM_INVALID;
  405. if (prec->Enable.ZeroDivide)
  406. (*pcw) &= ~IEM_ZERODIVIDE;
  407. if (prec->Enable.Overflow)
  408. (*pcw) &= ~IEM_OVERFLOW;
  409. if (prec->Enable.Underflow)
  410. (*pcw) &= ~IEM_UNDERFLOW;
  411. if (prec->Enable.Inexact)
  412. (*pcw) &= ~IEM_INEXACT;
  413. //
  414. // Update Rounding mode
  415. //
  416. switch (prec->RoundingMode) {
  417. case _FpRoundChopped:
  418. *pcw = *pcw & ~IMCW_RC | IRC_CHOP;
  419. break;
  420. case _FpRoundPlusInfinity:
  421. *pcw = *pcw & ~IMCW_RC | IRC_UP;
  422. break;
  423. case _FpRoundMinusInfinity:
  424. *pcw = *pcw & ~IMCW_RC | IRC_DOWN;
  425. break;
  426. case _FpRoundNearest:
  427. *pcw = *pcw & ~IMCW_RC | IRC_NEAR;
  428. break;
  429. }
  430. #ifdef _M_IX86
  431. //
  432. // Update Precision Control
  433. //
  434. switch (prec->Precision) {
  435. case _FpPrecisionFull:
  436. *pcw = *pcw & ~IMCW_RC | IPC_64;
  437. break;
  438. case _FpPrecision53:
  439. *pcw = *pcw & ~IMCW_RC | IPC_53;
  440. break;
  441. case _FpPrecision24:
  442. *pcw = *pcw & ~IMCW_RC | IPC_24;
  443. break;
  444. }
  445. #endif
  446. //
  447. // Update result
  448. //
  449. *presult = prec->Result.Value.Fp64Value;
  450. }
  451. /***
  452. * _handle_exc - produce masked response for IEEE fp exception
  453. *
  454. *Purpose:
  455. *
  456. *Entry:
  457. * unsigned int flags the exception flags
  458. * double *presult the default result
  459. * unsigned int cw user's fp control word
  460. *
  461. *Exit:
  462. * returns 1 on successful handling, 0 on failure
  463. * On success, *presult becomes the masked response
  464. *
  465. *Exceptions:
  466. *
  467. *******************************************************************************/
  468. int _handle_exc(unsigned int flags, double * presult, uintptr_t cw)
  469. {
  470. //
  471. // flags_p is useful for deciding whether there are still unhandled
  472. // exceptions in case multiple exceptions have occurred
  473. //
  474. int flags_p = flags & (FP_I | FP_Z | FP_O | FP_U | FP_P);
  475. if (flags & FP_I && cw & IEM_INVALID) {
  476. //
  477. // Masked response for invalid operation
  478. //
  479. _set_statfp(ISW_INVALID);
  480. flags_p &= ~FP_I;
  481. }
  482. else if (flags & FP_Z && cw & IEM_ZERODIVIDE) {
  483. //
  484. // Masked response for Division by zero
  485. // result should already have the proper value
  486. //
  487. _set_statfp( ISW_ZERODIVIDE);
  488. flags_p &= ~FP_Z;
  489. }
  490. else if (flags & FP_O && cw & IEM_OVERFLOW) {
  491. //
  492. // Masked response for Overflow
  493. //
  494. _set_statfp(ISW_OVERFLOW);
  495. switch (cw & IMCW_RC) {
  496. case IRC_NEAR:
  497. *presult = *presult > 0.0 ? D_INF : -D_INF;
  498. break;
  499. case IRC_UP:
  500. *presult = *presult > 0.0 ? D_INF : -D_MAX;
  501. break;
  502. case IRC_DOWN:
  503. *presult = *presult > 0.0 ? D_MAX : -D_INF;
  504. break;
  505. case IRC_CHOP:
  506. *presult = *presult > 0.0 ? D_MAX : -D_MAX;
  507. break;
  508. }
  509. flags_p &= ~FP_O;
  510. }
  511. else if (flags & FP_U && cw & IEM_UNDERFLOW) {
  512. //
  513. // Masked response for Underflow:
  514. // According to the IEEE standard, when the underflow trap is not
  515. // enabled, underflow shall be signaled only when both tininess
  516. // and loss of accuracy have been detected
  517. //
  518. int aloss=0; // loss of accuracy flag
  519. if (flags & FP_P) {
  520. aloss = 1;
  521. }
  522. //
  523. // a zero value in the result denotes
  524. // that even after ieee scaling, the exponent
  525. // was too small.
  526. // in this case the masked response is also
  527. // zero (sign is preserved)
  528. //
  529. if (*presult != 0.0) {
  530. double result;
  531. int expn, newexp;
  532. result = _decomp(*presult, &expn);
  533. newexp = expn - IEEE_ADJUST;
  534. if (newexp < MINEXP - 53) {
  535. result *= 0.0; // produce a signed zero
  536. aloss = 1;
  537. }
  538. else {
  539. int neg = result < 0; // save sign
  540. //
  541. // denormalize result
  542. //
  543. (*D_EXP(result)) &= 0x000f; /* clear exponent field */
  544. (*D_EXP(result)) |= 0x0010; /* set hidden bit */
  545. for (;newexp<MINEXP;newexp++) {
  546. if (*D_LO(result) & 0x1 && !aloss) {
  547. aloss = 1;
  548. }
  549. /* shift mantissa to the right */
  550. (*D_LO(result)) >>= 1;
  551. if (*D_HI(result) & 0x1) {
  552. (*D_LO(result)) |= 0x80000000;
  553. }
  554. (*D_HI(result)) >>= 1;
  555. }
  556. if (neg) {
  557. result = -result; // restore sign
  558. }
  559. }
  560. *presult = result;
  561. }
  562. else {
  563. aloss = 1;
  564. }
  565. if (aloss) {
  566. _set_statfp(ISW_UNDERFLOW);
  567. }
  568. flags_p &= ~FP_U;
  569. }
  570. //
  571. // Separate check for precision exception
  572. // (may coexist with overflow or underflow)
  573. //
  574. if (flags & FP_P && cw & IEM_INEXACT) {
  575. //
  576. // Masked response for inexact result
  577. //
  578. _set_statfp(ISW_INEXACT);
  579. flags_p &= ~FP_P;
  580. }
  581. return flags_p ? 0: 1;
  582. }
  583. /***
  584. * _umatherr - call user's matherr routine
  585. *
  586. *Purpose:
  587. * call user's matherr routine and set errno if appropriate
  588. *
  589. *
  590. *Entry:
  591. * int type type of excpetion
  592. * unsigned int opcode fp function that caused the exception
  593. * double arg1 first argument of the fp function
  594. * double arg2 second argument of the fp function
  595. * double retval return value of the fp function
  596. * unsigned int cw user's fp control word
  597. *
  598. *Exit:
  599. * fp control word becomes the user's fp cw
  600. * errno modified if user's matherr returns 0
  601. * return value the retval entered by the user in
  602. * the _exception matherr struct
  603. *
  604. *Exceptions:
  605. *
  606. *******************************************************************************/
  607. double _umatherr(
  608. int type,
  609. unsigned int opcode,
  610. double arg1,
  611. double arg2,
  612. double retval,
  613. uintptr_t cw
  614. )
  615. {
  616. struct _exception exc;
  617. //
  618. // call matherr only if the name of the function
  619. // is registered in the table, i.e., only if exc.name is valid
  620. //
  621. if (exc.name = _get_fname(opcode)) {
  622. exc.type = type;
  623. COPY_DOUBLE(&exc.arg1,&arg1);
  624. COPY_DOUBLE(&exc.arg2,&arg2);
  625. COPY_DOUBLE(&exc.retval,&retval);
  626. _rstorfp(cw);
  627. if (_matherr(&exc) == 0) {
  628. _set_errno(type);
  629. }
  630. return exc.retval;
  631. }
  632. else {
  633. //
  634. // treat this case as if matherr returned 0
  635. //
  636. _rstorfp(cw);
  637. _set_errno(type);
  638. return retval;
  639. }
  640. }
  641. /***
  642. * _set_errno - set errno
  643. *
  644. *Purpose:
  645. * set correct error value for errno
  646. *
  647. *Entry:
  648. * int matherrtype: the type of math error
  649. *
  650. *Exit:
  651. * modifies errno
  652. *
  653. *Exceptions:
  654. *
  655. *******************************************************************************/
  656. void _set_errno(int matherrtype)
  657. {
  658. switch(matherrtype) {
  659. case _DOMAIN:
  660. errno = EDOM;
  661. break;
  662. case _OVERFLOW:
  663. case _SING:
  664. errno = ERANGE;
  665. break;
  666. }
  667. }
  668. /***
  669. * _get_fname - get function name
  670. *
  671. *Purpose:
  672. * returns the _matherr function name that corresponds to a
  673. * floating point opcode
  674. *
  675. *Entry:
  676. * _FP_OPERATION_CODE opcode
  677. *
  678. *Exit:
  679. * returns a pointer to a string
  680. *
  681. *Exceptions:
  682. *
  683. *******************************************************************************/
  684. #define OP_NUM 29 /* number of fp operations */
  685. static char *_get_fname(unsigned int opcode)
  686. {
  687. static struct {
  688. unsigned int opcode;
  689. char *name;
  690. } _names[OP_NUM] = {
  691. { OP_EXP, "exp" },
  692. { OP_POW, "pow" },
  693. { OP_LOG, "log" },
  694. { OP_LOG10, "log10"},
  695. { OP_SINH, "sinh"},
  696. { OP_COSH, "cosh"},
  697. { OP_TANH, "tanh"},
  698. { OP_ASIN, "asin"},
  699. { OP_ACOS, "acos"},
  700. { OP_ATAN, "atan"},
  701. { OP_ATAN2, "atan2"},
  702. { OP_SQRT, "sqrt"},
  703. { OP_SIN, "sin"},
  704. { OP_COS, "cos"},
  705. { OP_TAN, "tan"},
  706. { OP_CEIL, "ceil"},
  707. { OP_FLOOR, "floor"},
  708. { OP_ABS, "fabs"},
  709. { OP_MODF, "modf"},
  710. { OP_LDEXP, "ldexp"},
  711. { OP_CABS, "_cabs"},
  712. { OP_HYPOT, "_hypot"},
  713. { OP_FMOD, "fmod"},
  714. { OP_FREXP, "frexp"},
  715. { OP_Y0, "_y0"},
  716. { OP_Y1, "_y1"},
  717. { OP_YN, "_yn"},
  718. { OP_LOGB, "_logb"},
  719. { OP_NEXTAFTER, "_nextafter"}
  720. };
  721. int i;
  722. for (i=0;i<OP_NUM;i++) {
  723. if (_names[i].opcode == opcode)
  724. return _names[i].name;
  725. }
  726. return (char *)0;
  727. }
  728. /***
  729. * _errcode - get _matherr error code
  730. *
  731. *Purpose:
  732. * returns matherr type that corresponds to exception flags
  733. *
  734. *Entry:
  735. * flags: exception flags
  736. *
  737. *Exit:
  738. * returns matherr type
  739. *
  740. *Exceptions:
  741. *
  742. *******************************************************************************/
  743. int _errcode(unsigned int flags)
  744. {
  745. unsigned int errcode;
  746. if (flags & FP_TLOSS) {
  747. errcode = _TLOSS;
  748. }
  749. else if (flags & FP_I) {
  750. errcode = _DOMAIN;
  751. }
  752. else if (flags & FP_Z) {
  753. errcode = _SING;
  754. }
  755. else if (flags & FP_O) {
  756. errcode = _OVERFLOW;
  757. }
  758. else if (flags & FP_U) {
  759. errcode = _UNDERFLOW;
  760. }
  761. else {
  762. // FP_P
  763. errcode = 0;
  764. }
  765. return errcode;
  766. }