1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
15 Implementation of math family functions.
21 #include "pal/palinternal.h"
22 #include "pal/dbgmsg.h"
28 #endif // HAVE_IEEEFP_H
32 #define PAL_NAN_DBL sqrt(-1.0)
33 #define PAL_POSINF_DBL -log(0.0)
34 #define PAL_NEGINF_DBL log(0.0)
36 #define IS_DBL_NEGZERO(x) (((*((INT64*)((void*)&x))) & I64(0xFFFFFFFFFFFFFFFF)) == I64(0x8000000000000000))
38 SET_DEFAULT_DEBUG_CHANNEL(CRT);
44 Determines whether given double-precision floating point value is finite.
48 _finite returns a nonzero value (TRUE) if its argument x is not
49 infinite, that is, if -INF < x < +INF. It returns 0 (FALSE) if the
50 argument is infinite or a NaN.
54 x Double-precision floating-point value
57 int __cdecl _finite(double x)
61 ENTRY("_finite (x=%f)\n", x);
63 #if defined(_IA64_) && defined (_HPUX_)
64 ret = !isnan(x) && (x != PAL_POSINF_DBL) && (x != PAL_NEGINF_DBL);
69 LOGEXIT("_finite returns int %d\n", ret);
80 int __cdecl _isnan(double x)
84 ENTRY("_isnan (x=%f)\n", x);
88 LOGEXIT("_isnan returns int %d\n", ret);
99 double __cdecl _copysign(double x, double y)
102 PERF_ENTRY(_copysign);
103 ENTRY("_copysign (x=%f, y=%f)\n", x, y);
105 ret = copysign(x, y);
107 LOGEXIT("_copysign returns double %f\n", ret);
108 PERF_EXIT(_copysign);
118 PALIMPORT double __cdecl PAL_acos(double x)
122 ENTRY("acos (x=%f)\n", x);
124 #if !HAVE_COMPATIBLE_ACOS
126 #endif // HAVE_COMPATIBLE_ACOS
130 #if !HAVE_COMPATIBLE_ACOS
133 ret = PAL_NAN_DBL; // NaN
135 #endif // HAVE_COMPATIBLE_ACOS
137 LOGEXIT("acos returns double %f\n", ret);
148 PALIMPORT double __cdecl PAL_asin(double x)
152 ENTRY("asin (x=%f)\n", x);
154 #if !HAVE_COMPATIBLE_ASIN
156 #endif // HAVE_COMPATIBLE_ASIN
160 #if !HAVE_COMPATIBLE_ASIN
163 ret = PAL_NAN_DBL; // NaN
165 #endif // HAVE_COMPATIBLE_ASIN
167 LOGEXIT("asin returns double %f\n", ret);
178 PALIMPORT double __cdecl PAL_atan2(double y, double x)
182 ENTRY("atan2 (y=%f, x=%f)\n", y, x);
184 #if !HAVE_COMPATIBLE_ATAN2
186 #endif // !HAVE_COMPATIBLE_ATAN2
190 #if !HAVE_COMPATIBLE_ATAN2
191 if ((errno == EDOM) && (x == 0.0) && (y == 0.0))
193 const double sign_x = copysign(1.0, x);
194 const double sign_y = copysign(1.0, y);
198 ret = copysign(0.0, sign_y);
202 ret = copysign(atan2(0.0, -1.0), sign_y);
205 #endif // !HAVE_COMPATIBLE_ATAN2
207 LOGEXIT("atan2 returns double %f\n", ret);
218 PALIMPORT double __cdecl PAL_exp(double x)
222 ENTRY("exp (x=%f)\n", x);
224 #if !HAVE_COMPATIBLE_EXP
231 #endif // HAVE_COMPATIBLE_EXP
235 #if !HAVE_COMPATIBLE_EXP
237 #endif // HAVE_COMPATIBLE_EXP
239 LOGEXIT("exp returns double %f\n", ret);
250 PALIMPORT LONG __cdecl PAL_labs(LONG l)
254 ENTRY("labs (l=%ld)\n", l);
258 LOGEXIT("labs returns long %ld\n", lRet);
260 return (LONG)lRet; // This explicit cast to LONG is used to silence any potential warnings due to implicitly casting the native long lRet to LONG when returning.
269 PALIMPORT double __cdecl PAL_log(double x)
273 ENTRY("log (x=%f)\n", x);
275 #if !HAVE_COMPATIBLE_LOG
277 #endif // !HAVE_COMPATIBLE_LOG
281 #if !HAVE_COMPATIBLE_LOG
282 if ((errno == EDOM) && (x < 0))
284 ret = PAL_NAN_DBL; // NaN
286 #endif // !HAVE_COMPATIBLE_LOG
288 LOGEXIT("log returns double %f\n", ret);
299 PALIMPORT double __cdecl PAL_log10(double x)
303 ENTRY("log10 (x=%f)\n", x);
305 #if !HAVE_COMPATIBLE_LOG10
307 #endif // !HAVE_COMPATIBLE_LOG10
311 #if !HAVE_COMPATIBLE_LOG10
312 if ((errno == EDOM) && (x < 0))
314 ret = PAL_NAN_DBL; // NaN
316 #endif // !HAVE_COMPATIBLE_LOG10
318 LOGEXIT("log10 returns double %f\n", ret);
329 PALIMPORT double __cdecl PAL_pow(double x, double y)
333 ENTRY("pow (x=%f, y=%f)\n", x, y);
335 #if !HAVE_COMPATIBLE_POW
336 if ((y == PAL_POSINF_DBL) && !isnan(x)) // +Inf
344 ret = PAL_NAN_DBL; // NaN
346 else if ((x > -1.0) && (x < 1.0))
352 ret = PAL_POSINF_DBL; // +Inf
355 else if ((y == PAL_NEGINF_DBL) && !isnan(x)) // -Inf
363 ret = PAL_NAN_DBL; // NaN
365 else if ((x > -1.0) && (x < 1.0))
367 ret = PAL_POSINF_DBL; // +Inf
374 else if (IS_DBL_NEGZERO(x) && (y == -1.0))
376 ret = PAL_NEGINF_DBL; // -Inf
378 else if ((x == 0.0) && (y < 0.0))
380 ret = PAL_POSINF_DBL; // +Inf
383 #endif // !HAVE_COMPATIBLE_POW
385 if ((y == 0.0) && isnan(x))
387 // Windows returns NaN for pow(NaN, 0), but POSIX specifies
388 // a return value of 1 for that case. We need to return
389 // the same result as Windows.
397 #if !HAVE_VALID_NEGATIVE_INF_POW
398 if ((ret == PAL_POSINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) != floor(y / 2)))
400 ret = PAL_NEGINF_DBL; // -Inf
402 #endif // !HAVE_VALID_NEGATIVE_INF_POW
404 #if !HAVE_VALID_POSITIVE_INF_POW
406 * The even/odd test in the if (this one and the one above) used to be ((long long) y % 2 == 0)
407 * on SPARC (long long) y for large y (>2**63) is always 0x7fffffff7fffffff, which
408 * is an odd number, so the test ((long long) y % 2 == 0) will always fail for
409 * large y. Since large double numbers are always even (e.g., the representation of
410 * 1E20+1 is the same as that of 1E20, the last .+1. is too insignificant to be part
411 * of the representation), this test will always return the wrong result for large y.
413 * The (ceil(y/2) == floor(y/2)) test is slower, but more robust.
415 if ((ret == PAL_NEGINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) == floor(y / 2)))
417 ret = PAL_POSINF_DBL; // +Inf
419 #endif // !HAVE_VALID_POSITIVE_INF_POW
421 LOGEXIT("pow returns double %f\n", ret);