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