1 /*
2  *  IEEE double helpers.
3  */
4 
5 #include "duk_internal.h"
6 
duk_double_is_anyinf(duk_double_t x)7 DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) {
8 	duk_double_union du;
9 	du.d = x;
10 	return DUK_DBLUNION_IS_ANYINF(&du);
11 }
12 
duk_double_is_posinf(duk_double_t x)13 DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) {
14 	duk_double_union du;
15 	du.d = x;
16 	return DUK_DBLUNION_IS_POSINF(&du);
17 }
18 
duk_double_is_neginf(duk_double_t x)19 DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) {
20 	duk_double_union du;
21 	du.d = x;
22 	return DUK_DBLUNION_IS_NEGINF(&du);
23 }
24 
duk_double_is_nan(duk_double_t x)25 DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) {
26 	duk_double_union du;
27 	du.d = x;
28 	/* Assumes we're dealing with a Duktape internal NaN which is
29 	 * NaN normalized if duk_tval requires it.
30 	 */
31 	DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
32 	return DUK_DBLUNION_IS_NAN(&du);
33 }
34 
duk_double_is_nan_or_zero(duk_double_t x)35 DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) {
36 	duk_double_union du;
37 	du.d = x;
38 	/* Assumes we're dealing with a Duktape internal NaN which is
39 	 * NaN normalized if duk_tval requires it.
40 	 */
41 	DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
42 	return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du);
43 }
44 
duk_double_is_nan_or_inf(duk_double_t x)45 DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) {
46 	duk_double_union du;
47 	du.d = x;
48 	/* If exponent is 0x7FF the argument is either a NaN or an
49 	 * infinity.  We don't need to check any other fields.
50 	 */
51 #if defined(DUK_USE_64BIT_OPS)
52 #if defined(DUK_USE_DOUBLE_ME)
53 	return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000);
54 #else
55 	return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000);
56 #endif
57 #else
58 	return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL;
59 #endif
60 }
61 
duk_double_is_nan_zero_inf(duk_double_t x)62 DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) {
63 	duk_double_union du;
64 #if defined(DUK_USE_64BIT_OPS)
65 	duk_uint64_t t;
66 #else
67 	duk_uint32_t t;
68 #endif
69 	du.d = x;
70 #if defined(DUK_USE_64BIT_OPS)
71 #if defined(DUK_USE_DOUBLE_ME)
72 	t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000);
73 	if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
74 		t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000);
75 		return t == 0;
76 	}
77 	if (t == DUK_U64_CONSTANT(0x000000007ff00000)) {
78 		return 1;
79 	}
80 #else
81 	t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000);
82 	if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
83 		t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000);
84 		return t == 0;
85 	}
86 	if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) {
87 		return 1;
88 	}
89 #endif
90 #else
91 	t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL;
92 	if (t == 0x00000000UL) {
93 		return DUK_DBLUNION_IS_ANYZERO(&du);
94 	}
95 	if (t == 0x7ff00000UL) {
96 		return 1;
97 	}
98 #endif
99 	return 0;
100 }
101 
duk_double_signbit(duk_double_t x)102 DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) {
103 	duk_double_union du;
104 	du.d = x;
105 	return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du);
106 }
107 
duk_double_trunc_towards_zero(duk_double_t x)108 DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) {
109 	/* XXX: optimize */
110 	duk_small_uint_t s = duk_double_signbit(x);
111 	x = DUK_FLOOR(DUK_FABS(x));  /* truncate towards zero */
112 	if (s) {
113 		x = -x;
114 	}
115 	return x;
116 }
117 
duk_double_same_sign(duk_double_t x,duk_double_t y)118 DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) {
119 	duk_double_union du1;
120 	duk_double_union du2;
121 	du1.d = x;
122 	du2.d = y;
123 
124 	return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0);
125 }
126 
duk_double_fmin(duk_double_t x,duk_double_t y)127 DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) {
128 	/* Doesn't replicate fmin() behavior exactly: for fmin() if one
129 	 * argument is a NaN, the other argument should be returned.
130 	 * Duktape doesn't rely on this behavior so the replacement can
131 	 * be simplified.
132 	 */
133 	return (x < y ? x : y);
134 }
135 
duk_double_fmax(duk_double_t x,duk_double_t y)136 DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) {
137 	/* Doesn't replicate fmax() behavior exactly: for fmax() if one
138 	 * argument is a NaN, the other argument should be returned.
139 	 * Duktape doesn't rely on this behavior so the replacement can
140 	 * be simplified.
141 	 */
142 	return (x > y ? x : y);
143 }
144 
duk_double_is_finite(duk_double_t x)145 DUK_INTERNAL duk_bool_t duk_double_is_finite(duk_double_t x) {
146 	return !duk_double_is_nan_or_inf(x);
147 }
148 
duk_double_is_integer(duk_double_t x)149 DUK_INTERNAL duk_bool_t duk_double_is_integer(duk_double_t x) {
150 	if (duk_double_is_nan_or_inf(x)) {
151 		return 0;
152 	} else {
153 		return duk_double_equals(duk_js_tointeger_number(x), x);
154 	}
155 }
156 
duk_double_is_safe_integer(duk_double_t x)157 DUK_INTERNAL duk_bool_t duk_double_is_safe_integer(duk_double_t x) {
158 	/* >>> 2**53-1
159 	 * 9007199254740991
160 	 */
161 	return duk_double_is_integer(x) && DUK_FABS(x) <= 9007199254740991.0;
162 }
163 
164 /* Check whether a duk_double_t is a whole number in the 32-bit range (reject
165  * negative zero), and if so, return a duk_int32_t.
166  * For compiler use: don't allow negative zero as it will cause trouble with
167  * LDINT+LDINTX, positive zero is OK.
168  */
duk_is_whole_get_int32_nonegzero(duk_double_t x,duk_int32_t * ival)169 DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) {
170 	duk_int32_t t;
171 
172 	t = duk_double_to_int32_t(x);
173 	if (!duk_double_equals((duk_double_t) t, x)) {
174 		return 0;
175 	}
176 	if (t == 0) {
177 		duk_double_union du;
178 		du.d = x;
179 		if (DUK_DBLUNION_HAS_SIGNBIT(&du)) {
180 			return 0;
181 		}
182 	}
183 	*ival = t;
184 	return 1;
185 }
186 
187 /* Check whether a duk_double_t is a whole number in the 32-bit range, and if
188  * so, return a duk_int32_t.
189  */
duk_is_whole_get_int32(duk_double_t x,duk_int32_t * ival)190 DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
191 	duk_int32_t t;
192 
193 	t = duk_double_to_int32_t(x);
194 	if (!duk_double_equals((duk_double_t) t, x)) {
195 		return 0;
196 	}
197 	*ival = t;
198 	return 1;
199 }
200 
201 /* Division: division by zero is undefined behavior (and may in fact trap)
202  * so it needs special handling for portability.
203  */
204 
duk_double_div(duk_double_t x,duk_double_t y)205 DUK_INTERNAL DUK_INLINE duk_double_t duk_double_div(duk_double_t x, duk_double_t y) {
206 #if !defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
207 	if (DUK_UNLIKELY(duk_double_equals(y, 0.0) != 0)) {
208 		/* In C99+ division by zero is undefined behavior so
209 		 * avoid it entirely.  Hopefully the compiler is
210 		 * smart enough to avoid emitting any actual code
211 		 * because almost all practical platforms behave as
212 		 * expected.
213 		 */
214 		if (x > 0.0) {
215 			if (DUK_SIGNBIT(y)) {
216 				return -DUK_DOUBLE_INFINITY;
217 			} else {
218 				return DUK_DOUBLE_INFINITY;
219 			}
220 		} else if (x < 0.0) {
221 			if (DUK_SIGNBIT(y)) {
222 				return DUK_DOUBLE_INFINITY;
223 			} else {
224 				return -DUK_DOUBLE_INFINITY;
225 			}
226 		} else {
227 			/* +/- 0, NaN */
228 			return DUK_DOUBLE_NAN;
229 		}
230 	}
231 #endif
232 
233 	return x / y;
234 }
235 
236 /* Double and float byteorder changes. */
237 
duk_dblunion_host_to_little(duk_double_union * u)238 DUK_INTERNAL DUK_INLINE void duk_dblunion_host_to_little(duk_double_union *u) {
239 #if defined(DUK_USE_DOUBLE_LE)
240 	/* HGFEDCBA -> HGFEDCBA */
241 	DUK_UNREF(u);
242 #elif defined(DUK_USE_DOUBLE_ME)
243 	duk_uint32_t a, b;
244 
245 	/* DCBAHGFE -> HGFEDCBA */
246 	a = u->ui[0];
247 	b = u->ui[1];
248 	u->ui[0] = b;
249 	u->ui[1] = a;
250 #elif defined(DUK_USE_DOUBLE_BE)
251 	/* ABCDEFGH -> HGFEDCBA */
252 #if defined(DUK_USE_64BIT_OPS)
253 	u->ull[0] = DUK_BSWAP64(u->ull[0]);
254 #else
255 	duk_uint32_t a, b;
256 
257 	a = u->ui[0];
258 	b = u->ui[1];
259 	u->ui[0] = DUK_BSWAP32(b);
260 	u->ui[1] = DUK_BSWAP32(a);
261 #endif
262 #else
263 #error internal error
264 #endif
265 }
266 
duk_dblunion_little_to_host(duk_double_union * u)267 DUK_INTERNAL DUK_INLINE void duk_dblunion_little_to_host(duk_double_union *u) {
268 	duk_dblunion_host_to_little(u);
269 }
270 
duk_dblunion_host_to_big(duk_double_union * u)271 DUK_INTERNAL DUK_INLINE void duk_dblunion_host_to_big(duk_double_union *u) {
272 #if defined(DUK_USE_DOUBLE_LE)
273 	/* HGFEDCBA -> ABCDEFGH */
274 #if defined(DUK_USE_64BIT_OPS)
275 	u->ull[0] = DUK_BSWAP64(u->ull[0]);
276 #else
277 	duk_uint32_t a, b;
278 
279 	a = u->ui[0];
280 	b = u->ui[1];
281 	u->ui[0] = DUK_BSWAP32(b);
282 	u->ui[1] = DUK_BSWAP32(a);
283 #endif
284 #elif defined(DUK_USE_DOUBLE_ME)
285 	duk_uint32_t a, b;
286 
287 	/* DCBAHGFE -> ABCDEFGH */
288 	a = u->ui[0];
289 	b = u->ui[1];
290 	u->ui[0] = DUK_BSWAP32(a);
291 	u->ui[1] = DUK_BSWAP32(b);
292 #elif defined(DUK_USE_DOUBLE_BE)
293 	/* ABCDEFGH -> ABCDEFGH */
294 	DUK_UNREF(u);
295 #else
296 #error internal error
297 #endif
298 }
299 
duk_dblunion_big_to_host(duk_double_union * u)300 DUK_INTERNAL DUK_INLINE void duk_dblunion_big_to_host(duk_double_union *u) {
301 	duk_dblunion_host_to_big(u);
302 }
303 
duk_fltunion_host_to_big(duk_float_union * u)304 DUK_INTERNAL DUK_INLINE void duk_fltunion_host_to_big(duk_float_union *u) {
305 #if defined(DUK_USE_DOUBLE_LE) || defined(DUK_USE_DOUBLE_ME)
306 	/* DCBA -> ABCD */
307 	u->ui[0] = DUK_BSWAP32(u->ui[0]);
308 #elif defined(DUK_USE_DOUBLE_BE)
309 	/* ABCD -> ABCD */
310 	DUK_UNREF(u);
311 #else
312 #error internal error
313 #endif
314 }
315 
duk_fltunion_big_to_host(duk_float_union * u)316 DUK_INTERNAL DUK_INLINE void duk_fltunion_big_to_host(duk_float_union *u) {
317 	duk_fltunion_host_to_big(u);
318 }
319 
320 /* Comparison: ensures comparison operates on exactly correct types, avoiding
321  * some floating point comparison pitfalls (e.g. atan2() assertions failed on
322  * -m32 with direct comparison, even with explicit casts).
323  */
324 #if defined(DUK_USE_GCC_PRAGMAS)
325 #pragma GCC diagnostic push
326 #pragma GCC diagnostic ignored "-Wfloat-equal"
327 #elif defined(DUK_USE_CLANG_PRAGMAS)
328 #pragma clang diagnostic push
329 #pragma clang diagnostic ignored "-Wfloat-equal"
330 #endif
331 
duk_double_equals(duk_double_t x,duk_double_t y)332 DUK_INTERNAL DUK_ALWAYS_INLINE duk_bool_t duk_double_equals(duk_double_t x, duk_double_t y) {
333 	return x == y;
334 }
335 
duk_float_equals(duk_float_t x,duk_float_t y)336 DUK_INTERNAL DUK_ALWAYS_INLINE duk_bool_t duk_float_equals(duk_float_t x, duk_float_t y) {
337 	return x == y;
338 }
339 #if defined(DUK_USE_GCC_PRAGMAS)
340 #pragma GCC diagnostic pop
341 #elif defined(DUK_USE_CLANG_PRAGMAS)
342 #pragma clang diagnostic pop
343 #endif
344