scalar_ulp.inl 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  2. ///
  3. /// Developed at SunPro, a Sun Microsystems, Inc. business.
  4. /// Permission to use, copy, modify, and distribute this
  5. /// software is freely granted, provided that this notice
  6. /// is preserved.
  7. #include "../detail/type_float.hpp"
  8. #include "../ext/scalar_constants.hpp"
  9. #include <cmath>
  10. #include <cfloat>
  11. #if GLM_COMPILER & GLM_COMPILER_VC
  12. # pragma warning(push)
  13. # pragma warning(disable : 4127)
  14. # pragma warning(disable : 4365) // '=': signed/unsigned mismatch
  15. #elif GLM_COMPILER & GLM_COMPILER_CLANG
  16. # pragma clang diagnostic push
  17. # pragma clang diagnostic ignored "-Wsign-conversion"
  18. # pragma clang diagnostic ignored "-Wpadded"
  19. #endif
  20. typedef union
  21. {
  22. float value;
  23. /* FIXME: Assumes 32 bit int. */
  24. unsigned int word;
  25. } ieee_float_shape_type;
  26. typedef union
  27. {
  28. double value;
  29. struct
  30. {
  31. int lsw;
  32. int msw;
  33. } parts;
  34. } ieee_double_shape_type;
  35. #define GLM_EXTRACT_WORDS(ix0,ix1,d) \
  36. do { \
  37. ieee_double_shape_type ew_u; \
  38. ew_u.value = (d); \
  39. (ix0) = ew_u.parts.msw; \
  40. (ix1) = ew_u.parts.lsw; \
  41. } while (0)
  42. #define GLM_GET_FLOAT_WORD(i,d) \
  43. do { \
  44. ieee_float_shape_type gf_u; \
  45. gf_u.value = (d); \
  46. (i) = static_cast<int>(gf_u.word); \
  47. } while (0)
  48. #define GLM_SET_FLOAT_WORD(d,i) \
  49. do { \
  50. ieee_float_shape_type sf_u; \
  51. sf_u.word = static_cast<unsigned int>(i); \
  52. (d) = sf_u.value; \
  53. } while (0)
  54. #define GLM_INSERT_WORDS(d,ix0,ix1) \
  55. do { \
  56. ieee_double_shape_type iw_u; \
  57. iw_u.parts.msw = (ix0); \
  58. iw_u.parts.lsw = (ix1); \
  59. (d) = iw_u.value; \
  60. } while (0)
  61. namespace glm{
  62. namespace detail
  63. {
  64. GLM_FUNC_QUALIFIER float nextafterf(float x, float y)
  65. {
  66. volatile float t;
  67. int hx, hy, ix, iy;
  68. GLM_GET_FLOAT_WORD(hx, x);
  69. GLM_GET_FLOAT_WORD(hy, y);
  70. ix = hx & 0x7fffffff; // |x|
  71. iy = hy & 0x7fffffff; // |y|
  72. if((ix > 0x7f800000) || // x is nan
  73. (iy > 0x7f800000)) // y is nan
  74. return x + y;
  75. if(abs(y - x) <= epsilon<float>())
  76. return y; // x=y, return y
  77. if(ix == 0)
  78. { // x == 0
  79. GLM_SET_FLOAT_WORD(x, (hy & 0x80000000) | 1);// return +-minsubnormal
  80. t = x * x;
  81. if(abs(t - x) <= epsilon<float>())
  82. return t;
  83. else
  84. return x; // raise underflow flag
  85. }
  86. if(hx >= 0)
  87. { // x > 0
  88. if(hx > hy) // x > y, x -= ulp
  89. hx -= 1;
  90. else // x < y, x += ulp
  91. hx += 1;
  92. }
  93. else
  94. { // x < 0
  95. if(hy >= 0 || hx > hy) // x < y, x -= ulp
  96. hx -= 1;
  97. else // x > y, x += ulp
  98. hx += 1;
  99. }
  100. hy = hx & 0x7f800000;
  101. if(hy >= 0x7f800000)
  102. return x + x; // overflow
  103. if(hy < 0x00800000) // underflow
  104. {
  105. t = x * x;
  106. if(abs(t - x) > epsilon<float>())
  107. { // raise underflow flag
  108. GLM_SET_FLOAT_WORD(y, hx);
  109. return y;
  110. }
  111. }
  112. GLM_SET_FLOAT_WORD(x, hx);
  113. return x;
  114. }
  115. GLM_FUNC_QUALIFIER double nextafter(double x, double y)
  116. {
  117. volatile double t;
  118. int hx, hy, ix, iy;
  119. unsigned int lx, ly;
  120. GLM_EXTRACT_WORDS(hx, lx, x);
  121. GLM_EXTRACT_WORDS(hy, ly, y);
  122. ix = hx & 0x7fffffff; // |x|
  123. iy = hy & 0x7fffffff; // |y|
  124. if(((ix >= 0x7ff00000) && ((ix - 0x7ff00000) | lx) != 0) || // x is nan
  125. ((iy >= 0x7ff00000) && ((iy - 0x7ff00000) | ly) != 0)) // y is nan
  126. return x + y;
  127. if(abs(y - x) <= epsilon<double>())
  128. return y; // x=y, return y
  129. if((ix | lx) == 0)
  130. { // x == 0
  131. GLM_INSERT_WORDS(x, hy & 0x80000000, 1); // return +-minsubnormal
  132. t = x * x;
  133. if(abs(t - x) <= epsilon<double>())
  134. return t;
  135. else
  136. return x; // raise underflow flag
  137. }
  138. if(hx >= 0) { // x > 0
  139. if(hx > hy || ((hx == hy) && (lx > ly))) { // x > y, x -= ulp
  140. if(lx == 0) hx -= 1;
  141. lx -= 1;
  142. }
  143. else { // x < y, x += ulp
  144. lx += 1;
  145. if(lx == 0) hx += 1;
  146. }
  147. }
  148. else { // x < 0
  149. if(hy >= 0 || hx > hy || ((hx == hy) && (lx > ly))){// x < y, x -= ulp
  150. if(lx == 0) hx -= 1;
  151. lx -= 1;
  152. }
  153. else { // x > y, x += ulp
  154. lx += 1;
  155. if(lx == 0) hx += 1;
  156. }
  157. }
  158. hy = hx & 0x7ff00000;
  159. if(hy >= 0x7ff00000)
  160. return x + x; // overflow
  161. if(hy < 0x00100000)
  162. { // underflow
  163. t = x * x;
  164. if(abs(t - x) > epsilon<double>())
  165. { // raise underflow flag
  166. GLM_INSERT_WORDS(y, hx, lx);
  167. return y;
  168. }
  169. }
  170. GLM_INSERT_WORDS(x, hx, lx);
  171. return x;
  172. }
  173. }//namespace detail
  174. }//namespace glm
  175. #if GLM_COMPILER & GLM_COMPILER_VC
  176. # pragma warning(pop)
  177. #elif GLM_COMPILER & GLM_COMPILER_CLANG
  178. # pragma clang diagnostic pop
  179. #endif
  180. namespace glm
  181. {
  182. template<>
  183. GLM_FUNC_QUALIFIER float nextFloat(float x)
  184. {
  185. return std::nextafter(x, std::numeric_limits<float>::max());
  186. }
  187. template<>
  188. GLM_FUNC_QUALIFIER double nextFloat(double x)
  189. {
  190. return std::nextafter(x, std::numeric_limits<double>::max());
  191. }
  192. template<typename T>
  193. GLM_FUNC_QUALIFIER T nextFloat(T x, int ULPs)
  194. {
  195. static_assert(std::numeric_limits<T>::is_iec559 || GLM_CONFIG_UNRESTRICTED_FLOAT, "'nextFloat' only accept floating-point input");
  196. assert(ULPs >= 0);
  197. T temp = x;
  198. for(int i = 0; i < ULPs; ++i)
  199. temp = nextFloat(temp);
  200. return temp;
  201. }
  202. GLM_FUNC_QUALIFIER float prevFloat(float x)
  203. {
  204. return std::nextafter(x, std::numeric_limits<float>::min());
  205. }
  206. GLM_FUNC_QUALIFIER double prevFloat(double x)
  207. {
  208. return std::nextafter(x, std::numeric_limits<double>::min());
  209. }
  210. template<typename T>
  211. GLM_FUNC_QUALIFIER T prevFloat(T x, int ULPs)
  212. {
  213. static_assert(std::numeric_limits<T>::is_iec559 || GLM_CONFIG_UNRESTRICTED_FLOAT, "'prevFloat' only accept floating-point input");
  214. assert(ULPs >= 0);
  215. T temp = x;
  216. for(int i = 0; i < ULPs; ++i)
  217. temp = prevFloat(temp);
  218. return temp;
  219. }
  220. GLM_FUNC_QUALIFIER int floatDistance(float x, float y)
  221. {
  222. detail::float_t<float> const a(x);
  223. detail::float_t<float> const b(y);
  224. return abs(a.i - b.i);
  225. }
  226. GLM_FUNC_QUALIFIER int64 floatDistance(double x, double y)
  227. {
  228. detail::float_t<double> const a(x);
  229. detail::float_t<double> const b(y);
  230. return abs(a.i - b.i);
  231. }
  232. }//namespace glm