FPcontrol-Nt.c 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #include "lib9.h"
  2. #include <float.h>
  3. #include "mathi.h"
  4. void
  5. FPinit(void)
  6. {
  7. _controlfp(_EM_INEXACT,_MCW_EM); // abort on underflow, etc.
  8. }
  9. ulong
  10. getFPstatus(void)
  11. {
  12. ulong fsr = 0, fsr32 = _statusfp();
  13. if(fsr32&_SW_INEXACT) fsr |= INEX;
  14. if(fsr32&_SW_OVERFLOW) fsr |= OVFL;
  15. if(fsr32&_SW_UNDERFLOW) fsr |= UNFL;
  16. if(fsr32&_SW_ZERODIVIDE) fsr |= ZDIV;
  17. if(fsr32&_SW_INVALID) fsr |= INVAL;
  18. return fsr;
  19. }
  20. ulong
  21. FPstatus(ulong fsr, ulong mask)
  22. {
  23. ulong old = getFPstatus();
  24. fsr = (fsr&mask) | (old&~mask);
  25. if(fsr!=old){
  26. _clearfp();
  27. if(fsr){
  28. ulong fcr = _controlfp(0,0);
  29. double x = 1., y = 1e200, z = 0.;
  30. _controlfp(_MCW_EM,_MCW_EM);
  31. if(fsr&INEX) z = x + y;
  32. if(fsr&OVFL) z = y*y;
  33. if(fsr&UNFL) z = (x/y)/y;
  34. if(fsr&ZDIV) z = x/z;
  35. if(fsr&INVAL) z = z/z;
  36. _controlfp(fcr,_MCW_EM);
  37. }
  38. }
  39. return(old&mask);
  40. }
  41. ulong
  42. getFPcontrol(void)
  43. {
  44. ulong fcr, fcr32 = _controlfp(0,0);
  45. switch(fcr32&_MCW_RC){
  46. case _RC_NEAR: fcr = RND_NR; break;
  47. case _RC_DOWN: fcr = RND_NINF; break;
  48. case _RC_UP: fcr = RND_PINF; break;
  49. case _RC_CHOP: fcr = RND_Z; break;
  50. }
  51. if(!(fcr32&_EM_INEXACT)) fcr |= INEX;
  52. if(!(fcr32&_EM_OVERFLOW)) fcr |= OVFL;
  53. if(!(fcr32&_EM_UNDERFLOW)) fcr |= UNFL;
  54. if(!(fcr32&_EM_ZERODIVIDE)) fcr |= ZDIV;
  55. if(!(fcr32&_EM_INVALID)) fcr |= INVAL;
  56. return fcr;
  57. }
  58. ulong
  59. FPcontrol(ulong fcr, ulong mask)
  60. {
  61. ulong old = getFPcontrol();
  62. ulong fcr32 = _MCW_EM, mask32 = _MCW_RC|_MCW_EM;
  63. fcr = (fcr&mask) | (old&~mask);
  64. if(fcr&INEX) fcr32 ^= _EM_INEXACT;
  65. if(fcr&OVFL) fcr32 ^= _EM_OVERFLOW;
  66. if(fcr&UNFL) fcr32 ^= _EM_UNDERFLOW;
  67. if(fcr&ZDIV) fcr32 ^= _EM_ZERODIVIDE;
  68. if(fcr&INVAL) fcr32 ^= _EM_INVALID;
  69. switch(fcr&RND_MASK){
  70. case RND_NR: fcr32 |= _RC_NEAR; break;
  71. case RND_NINF: fcr32 |= _RC_DOWN; break;
  72. case RND_PINF: fcr32 |= _RC_UP; break;
  73. case RND_Z: fcr32 |= _RC_CHOP; break;
  74. }
  75. _controlfp(fcr32,mask32);
  76. return(old&mask);
  77. }