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 #define PAL_NAN_FLT sqrtf(-1.0f)
39 #define PAL_POSINF_FLT -logf(0.0f)
40 #define PAL_NEGINF_FLT logf(0.0f)
42 #define IS_FLT_NEGZERO(x) (((*((INT32*)((void*)&x))) & 0xFFFFFFFF) == 0x80000000)
44 SET_DEFAULT_DEBUG_CHANNEL(CRT);
50 Determines whether given double-precision floating point value is finite.
54 _finite returns a nonzero value (TRUE) if its argument x is not
55 infinite, that is, if -INF < x < +INF. It returns 0 (FALSE) if the
56 argument is infinite or a NaN.
60 x Double-precision floating-point value
63 int __cdecl _finite(double x)
67 ENTRY("_finite (x=%f)\n", x);
69 #if defined(_IA64_) && defined (_HPUX_)
70 ret = !isnan(x) && (x != PAL_POSINF_DBL) && (x != PAL_NEGINF_DBL);
75 LOGEXIT("_finite returns int %d\n", ret);
86 int __cdecl _isnan(double x)
90 ENTRY("_isnan (x=%f)\n", x);
94 LOGEXIT("_isnan returns int %d\n", ret);
105 double __cdecl _copysign(double x, double y)
108 PERF_ENTRY(_copysign);
109 ENTRY("_copysign (x=%f, y=%f)\n", x, y);
111 ret = copysign(x, y);
113 LOGEXIT("_copysign returns double %f\n", ret);
114 PERF_EXIT(_copysign);
124 PALIMPORT double __cdecl PAL_acos(double x)
128 ENTRY("acos (x=%f)\n", x);
130 #if !HAVE_COMPATIBLE_ACOS
132 #endif // HAVE_COMPATIBLE_ACOS
136 #if !HAVE_COMPATIBLE_ACOS
139 ret = PAL_NAN_DBL; // NaN
141 #endif // HAVE_COMPATIBLE_ACOS
143 LOGEXIT("acos returns double %f\n", ret);
154 PALIMPORT double __cdecl PAL_asin(double x)
158 ENTRY("asin (x=%f)\n", x);
160 #if !HAVE_COMPATIBLE_ASIN
162 #endif // HAVE_COMPATIBLE_ASIN
166 #if !HAVE_COMPATIBLE_ASIN
169 ret = PAL_NAN_DBL; // NaN
171 #endif // HAVE_COMPATIBLE_ASIN
173 LOGEXIT("asin returns double %f\n", ret);
184 PALIMPORT double __cdecl PAL_atan2(double y, double x)
188 ENTRY("atan2 (y=%f, x=%f)\n", y, x);
190 #if !HAVE_COMPATIBLE_ATAN2
192 #endif // !HAVE_COMPATIBLE_ATAN2
196 #if !HAVE_COMPATIBLE_ATAN2
197 if ((errno == EDOM) && (x == 0.0) && (y == 0.0))
199 const double sign_x = copysign(1.0, x);
200 const double sign_y = copysign(1.0, y);
204 ret = copysign(0.0, sign_y);
208 ret = copysign(atan2(0.0, -1.0), sign_y);
211 #endif // !HAVE_COMPATIBLE_ATAN2
213 LOGEXIT("atan2 returns double %f\n", ret);
224 PALIMPORT double __cdecl PAL_exp(double x)
228 ENTRY("exp (x=%f)\n", x);
230 #if !HAVE_COMPATIBLE_EXP
237 #endif // HAVE_COMPATIBLE_EXP
241 #if !HAVE_COMPATIBLE_EXP
243 #endif // HAVE_COMPATIBLE_EXP
245 LOGEXIT("exp returns double %f\n", ret);
256 PALIMPORT LONG __cdecl PAL_labs(LONG l)
260 ENTRY("labs (l=%ld)\n", l);
264 LOGEXIT("labs returns long %ld\n", lRet);
266 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.
275 PALIMPORT double __cdecl PAL_log(double x)
279 ENTRY("log (x=%f)\n", x);
281 #if !HAVE_COMPATIBLE_LOG
283 #endif // !HAVE_COMPATIBLE_LOG
287 #if !HAVE_COMPATIBLE_LOG
288 if ((errno == EDOM) && (x < 0))
290 ret = PAL_NAN_DBL; // NaN
292 #endif // !HAVE_COMPATIBLE_LOG
294 LOGEXIT("log returns double %f\n", ret);
305 PALIMPORT double __cdecl PAL_log10(double x)
309 ENTRY("log10 (x=%f)\n", x);
311 #if !HAVE_COMPATIBLE_LOG10
313 #endif // !HAVE_COMPATIBLE_LOG10
317 #if !HAVE_COMPATIBLE_LOG10
318 if ((errno == EDOM) && (x < 0))
320 ret = PAL_NAN_DBL; // NaN
322 #endif // !HAVE_COMPATIBLE_LOG10
324 LOGEXIT("log10 returns double %f\n", ret);
335 PALIMPORT double __cdecl PAL_pow(double x, double y)
339 ENTRY("pow (x=%f, y=%f)\n", x, y);
341 #if !HAVE_COMPATIBLE_POW
342 if ((y == PAL_POSINF_DBL) && !isnan(x)) // +Inf
350 ret = PAL_NAN_DBL; // NaN
352 else if ((x > -1.0) && (x < 1.0))
358 ret = PAL_POSINF_DBL; // +Inf
361 else if ((y == PAL_NEGINF_DBL) && !isnan(x)) // -Inf
369 ret = PAL_NAN_DBL; // NaN
371 else if ((x > -1.0) && (x < 1.0))
373 ret = PAL_POSINF_DBL; // +Inf
380 else if (IS_DBL_NEGZERO(x) && (y == -1.0))
382 ret = PAL_NEGINF_DBL; // -Inf
384 else if ((x == 0.0) && (y < 0.0))
386 ret = PAL_POSINF_DBL; // +Inf
389 #endif // !HAVE_COMPATIBLE_POW
391 if ((y == 0.0) && isnan(x))
393 // Windows returns NaN for pow(NaN, 0), but POSIX specifies
394 // a return value of 1 for that case. We need to return
395 // the same result as Windows.
403 #if !HAVE_VALID_NEGATIVE_INF_POW
404 if ((ret == PAL_POSINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) != floor(y / 2)))
406 ret = PAL_NEGINF_DBL; // -Inf
408 #endif // !HAVE_VALID_NEGATIVE_INF_POW
410 #if !HAVE_VALID_POSITIVE_INF_POW
412 * The even/odd test in the if (this one and the one above) used to be ((long long) y % 2 == 0)
413 * on SPARC (long long) y for large y (>2**63) is always 0x7fffffff7fffffff, which
414 * is an odd number, so the test ((long long) y % 2 == 0) will always fail for
415 * large y. Since large double numbers are always even (e.g., the representation of
416 * 1E20+1 is the same as that of 1E20, the last .+1. is too insignificant to be part
417 * of the representation), this test will always return the wrong result for large y.
419 * The (ceil(y/2) == floor(y/2)) test is slower, but more robust.
421 if ((ret == PAL_NEGINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) == floor(y / 2)))
423 ret = PAL_POSINF_DBL; // +Inf
425 #endif // !HAVE_VALID_POSITIVE_INF_POW
427 LOGEXIT("pow returns double %f\n", ret);
436 Determines whether given single-precision floating point value is finite.
440 _finitef returns a nonzero value (TRUE) if its argument x is not
441 infinite, that is, if -INF < x < +INF. It returns 0 (FALSE) if the
442 argument is infinite or a NaN.
446 x Single-precision floating-point value
449 int __cdecl _finitef(float x)
452 PERF_ENTRY(_finitef);
453 ENTRY("_finitef (x=%f)\n", x);
455 #if defined(_IA64_) && defined (_HPUX_)
456 ret = !isnan(x) && (x != PAL_POSINF_FLT) && (x != PAL_NEGINF_FLT);
461 LOGEXIT("_finitef returns int %d\n", ret);
472 int __cdecl _isnanf(float x)
476 ENTRY("_isnanf (x=%f)\n", x);
480 LOGEXIT("_isnanf returns int %d\n", ret);
491 float __cdecl _copysignf(float x, float y)
494 PERF_ENTRY(_copysignf);
495 ENTRY("_copysignf (x=%f, y=%f)\n", x, y);
497 ret = copysign(x, y);
499 LOGEXIT("_copysignf returns float %f\n", ret);
500 PERF_EXIT(_copysignf);
510 PALIMPORT float __cdecl PAL_acosf(float x)
514 ENTRY("acosf (x=%f)\n", x);
516 #if !HAVE_COMPATIBLE_ACOS
518 #endif // HAVE_COMPATIBLE_ACOS
522 #if !HAVE_COMPATIBLE_ACOS
525 ret = PAL_NAN_FLT; // NaN
527 #endif // HAVE_COMPATIBLE_ACOS
529 LOGEXIT("acosf returns float %f\n", ret);
540 PALIMPORT float __cdecl PAL_asinf(float x)
544 ENTRY("asinf (x=%f)\n", x);
546 #if !HAVE_COMPATIBLE_ASIN
548 #endif // HAVE_COMPATIBLE_ASIN
552 #if !HAVE_COMPATIBLE_ASIN
555 ret = PAL_NAN_FLT; // NaN
557 #endif // HAVE_COMPATIBLE_ASIN
559 LOGEXIT("asinf returns float %f\n", ret);
570 PALIMPORT float __cdecl PAL_atan2f(float y, float x)
574 ENTRY("atan2f (y=%f, x=%f)\n", y, x);
576 #if !HAVE_COMPATIBLE_ATAN2
578 #endif // !HAVE_COMPATIBLE_ATAN2
582 #if !HAVE_COMPATIBLE_ATAN2
583 if ((errno == EDOM) && (x == 0.0f) && (y == 0.0f))
585 const float sign_x = copysign(1.0f, x);
586 const float sign_y = copysign(1.0f, y);
590 ret = copysign(0.0f, sign_y);
594 ret = copysign(atan2f(0.0f, -1.0f), sign_y);
597 #endif // !HAVE_COMPATIBLE_ATAN2
599 LOGEXIT("atan2f returns float %f\n", ret);
610 PALIMPORT float __cdecl PAL_expf(float x)
614 ENTRY("expf (x=%f)\n", x);
616 #if !HAVE_COMPATIBLE_EXP
623 #endif // HAVE_COMPATIBLE_EXP
627 #if !HAVE_COMPATIBLE_EXP
629 #endif // HAVE_COMPATIBLE_EXP
631 LOGEXIT("expf returns float %f\n", ret);
642 PALIMPORT float __cdecl PAL_logf(float x)
646 ENTRY("logf (x=%f)\n", x);
648 #if !HAVE_COMPATIBLE_LOG
650 #endif // !HAVE_COMPATIBLE_LOG
654 #if !HAVE_COMPATIBLE_LOG
655 if ((errno == EDOM) && (x < 0))
657 ret = PAL_NAN_FLT; // NaN
659 #endif // !HAVE_COMPATIBLE_LOG
661 LOGEXIT("logf returns float %f\n", ret);
672 PALIMPORT float __cdecl PAL_log10f(float x)
676 ENTRY("log10f (x=%f)\n", x);
678 #if !HAVE_COMPATIBLE_LOG10
680 #endif // !HAVE_COMPATIBLE_LOG10
684 #if !HAVE_COMPATIBLE_LOG10
685 if ((errno == EDOM) && (x < 0))
687 ret = PAL_NAN_FLT; // NaN
689 #endif // !HAVE_COMPATIBLE_LOG10
691 LOGEXIT("log10f returns float %f\n", ret);
702 PALIMPORT float __cdecl PAL_powf(float x, float y)
706 ENTRY("powf (x=%f, y=%f)\n", x, y);
708 #if !HAVE_COMPATIBLE_POW
709 if ((y == PAL_POSINF_FLT) && !isnan(x)) // +Inf
717 ret = PAL_NAN_FLT; // NaN
719 else if ((x > -1.0f) && (x < 1.0f))
725 ret = PAL_POSINF_FLT; // +Inf
728 else if ((y == PAL_NEGINF_FLT) && !isnan(x)) // -Inf
736 ret = PAL_NAN_FLT; // NaN
738 else if ((x > -1.0f) && (x < 1.0f))
740 ret = PAL_POSINF_FLT; // +Inf
747 else if (IS_FLT_NEGZERO(x) && (y == -1.0f))
749 ret = PAL_NEGINF_FLT; // -Inf
751 else if ((x == 0.0f) && (y < 0.0f))
753 ret = PAL_POSINF_FLT; // +Inf
756 #endif // !HAVE_COMPATIBLE_POW
758 if ((y == 0.0f) && isnan(x))
760 // Windows returns NaN for powf(NaN, 0), but POSIX specifies
761 // a return value of 1 for that case. We need to return
762 // the same result as Windows.
770 #if !HAVE_VALID_NEGATIVE_INF_POW
771 if ((ret == PAL_POSINF_FLT) && (x < 0) && isfinite(x) && (ceilf(y / 2) != floorf(y / 2)))
773 ret = PAL_NEGINF_FLT; // -Inf
775 #endif // !HAVE_VALID_NEGATIVE_INF_POW
777 #if !HAVE_VALID_POSITIVE_INF_POW
779 * The (ceil(y/2) == floor(y/2)) test is slower, but more robust for platforms where large y
780 * will return the wrong result for ((long) y % 2 == 0). See PAL_pow(double) above for more details.
782 if ((ret == PAL_NEGINF_FLT) && (x < 0) && isfinite(x) && (ceilf(y / 2) == floorf(y / 2)))
784 ret = PAL_POSINF_FLT; // +Inf
786 #endif // !HAVE_VALID_POSITIVE_INF_POW
788 LOGEXIT("powf returns float %f\n", ret);