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