1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
14 Implementation of math family functions.
20 #include "pal/palinternal.h"
21 #include "pal/dbgmsg.h"
27 #endif // HAVE_IEEEFP_H
31 #define PAL_NAN_DBL sqrt(-1.0)
32 #define PAL_POSINF_DBL -log(0.0)
33 #define PAL_NEGINF_DBL log(0.0)
35 #define IS_DBL_NEGZERO(x) (((*((INT64*)((void*)&x))) & I64(0xFFFFFFFFFFFFFFFF)) == I64(0x8000000000000000))
37 #define PAL_NAN_FLT sqrtf(-1.0f)
38 #define PAL_POSINF_FLT -logf(0.0f)
39 #define PAL_NEGINF_FLT logf(0.0f)
41 #define IS_FLT_NEGZERO(x) (((*((INT32*)((void*)&x))) & 0xFFFFFFFF) == 0x80000000)
43 SET_DEFAULT_DEBUG_CHANNEL(CRT);
49 Determines whether given double-precision floating point value is finite.
53 _finite returns a nonzero value (TRUE) if its argument x is not
54 infinite, that is, if -INF < x < +INF. It returns 0 (FALSE) if the
55 argument is infinite or a NaN.
59 x Double-precision floating-point value
62 int __cdecl _finite(double x)
66 ENTRY("_finite (x=%f)\n", x);
70 LOGEXIT("_finite returns int %d\n", ret);
81 int __cdecl _isnan(double x)
85 ENTRY("_isnan (x=%f)\n", x);
89 LOGEXIT("_isnan returns int %d\n", ret);
100 double __cdecl _copysign(double x, double y)
103 PERF_ENTRY(_copysign);
104 ENTRY("_copysign (x=%f, y=%f)\n", x, y);
106 ret = copysign(x, y);
108 LOGEXIT("_copysign returns double %f\n", ret);
109 PERF_EXIT(_copysign);
119 PALIMPORT double __cdecl PAL_acos(double x)
123 ENTRY("acos (x=%f)\n", x);
125 #if !HAVE_COMPATIBLE_ACOS
127 #endif // HAVE_COMPATIBLE_ACOS
131 #if !HAVE_COMPATIBLE_ACOS
134 ret = PAL_NAN_DBL; // NaN
136 #endif // HAVE_COMPATIBLE_ACOS
138 LOGEXIT("acos returns double %f\n", ret);
149 PALIMPORT double __cdecl PAL_acosh(double x)
153 ENTRY("acosh (x=%f)\n", x);
157 LOGEXIT("acosh returns double %f\n", ret);
168 PALIMPORT double __cdecl PAL_asin(double x)
172 ENTRY("asin (x=%f)\n", x);
174 #if !HAVE_COMPATIBLE_ASIN
176 #endif // HAVE_COMPATIBLE_ASIN
180 #if !HAVE_COMPATIBLE_ASIN
183 ret = PAL_NAN_DBL; // NaN
185 #endif // HAVE_COMPATIBLE_ASIN
187 LOGEXIT("asin returns double %f\n", ret);
198 PALIMPORT double __cdecl PAL_asinh(double x)
202 ENTRY("asinh (x=%f)\n", x);
206 LOGEXIT("asinh returns double %f\n", ret);
217 PALIMPORT double __cdecl PAL_atan2(double y, double x)
221 ENTRY("atan2 (y=%f, x=%f)\n", y, x);
223 #if !HAVE_COMPATIBLE_ATAN2
225 #endif // !HAVE_COMPATIBLE_ATAN2
229 #if !HAVE_COMPATIBLE_ATAN2
230 if ((errno == EDOM) && (x == 0.0) && (y == 0.0))
232 const double sign_x = copysign(1.0, x);
233 const double sign_y = copysign(1.0, y);
237 ret = copysign(0.0, sign_y);
241 ret = copysign(atan2(0.0, -1.0), sign_y);
244 #endif // !HAVE_COMPATIBLE_ATAN2
246 LOGEXIT("atan2 returns double %f\n", ret);
257 PALIMPORT double __cdecl PAL_exp(double x)
261 ENTRY("exp (x=%f)\n", x);
263 #if !HAVE_COMPATIBLE_EXP
270 #endif // HAVE_COMPATIBLE_EXP
274 #if !HAVE_COMPATIBLE_EXP
276 #endif // HAVE_COMPATIBLE_EXP
278 LOGEXIT("exp returns double %f\n", ret);
289 PALIMPORT double __cdecl PAL_fma(double x, double y, double z)
293 ENTRY("fma (x=%f, y=%f, z=%f)\n", x, y, z);
297 LOGEXIT("fma returns double %f\n", ret);
308 PALIMPORT int __cdecl PAL_ilogb(double x)
312 ENTRY("ilogb (x=%f)\n", x);
314 #if !HAVE_COMPATIBLE_ILOGB0
320 #endif // !HAVE_COMPATIBLE_ILOGB0
322 #if !HAVE_COMPATIBLE_ILOGBNAN
328 #endif // !HAVE_COMPATIBLE_ILOGBNAN
334 LOGEXIT("ilogb returns int %d\n", ret);
345 PALIMPORT double __cdecl PAL_log(double x)
349 ENTRY("log (x=%f)\n", x);
351 #if !HAVE_COMPATIBLE_LOG
353 #endif // !HAVE_COMPATIBLE_LOG
357 #if !HAVE_COMPATIBLE_LOG
358 if ((errno == EDOM) && (x < 0))
360 ret = PAL_NAN_DBL; // NaN
362 #endif // !HAVE_COMPATIBLE_LOG
364 LOGEXIT("log returns double %f\n", ret);
375 PALIMPORT double __cdecl PAL_log2(double x)
379 ENTRY("log2 (x=%f)\n", x);
383 LOGEXIT("log2 returns double %f\n", ret);
394 PALIMPORT double __cdecl PAL_log10(double x)
398 ENTRY("log10 (x=%f)\n", x);
400 #if !HAVE_COMPATIBLE_LOG10
402 #endif // !HAVE_COMPATIBLE_LOG10
406 #if !HAVE_COMPATIBLE_LOG10
407 if ((errno == EDOM) && (x < 0))
409 ret = PAL_NAN_DBL; // NaN
411 #endif // !HAVE_COMPATIBLE_LOG10
413 LOGEXIT("log10 returns double %f\n", ret);
424 PALIMPORT double __cdecl PAL_pow(double x, double y)
428 ENTRY("pow (x=%f, y=%f)\n", x, y);
430 #if !HAVE_COMPATIBLE_POW
431 if ((y == PAL_POSINF_DBL) && !isnan(x)) // +Inf
441 else if ((x > -1.0) && (x < 1.0))
447 ret = PAL_POSINF_DBL; // +Inf
450 else if ((y == PAL_NEGINF_DBL) && !isnan(x)) // -Inf
460 else if ((x > -1.0) && (x < 1.0))
462 ret = PAL_POSINF_DBL; // +Inf
469 else if (IS_DBL_NEGZERO(x) && (y == -1.0))
471 ret = PAL_NEGINF_DBL; // -Inf
473 else if ((x == 0.0) && (y < 0.0))
475 ret = PAL_POSINF_DBL; // +Inf
478 #endif // !HAVE_COMPATIBLE_POW
482 #if !HAVE_VALID_NEGATIVE_INF_POW
483 if ((ret == PAL_POSINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) != floor(y / 2)))
485 ret = PAL_NEGINF_DBL; // -Inf
487 #endif // !HAVE_VALID_NEGATIVE_INF_POW
489 #if !HAVE_VALID_POSITIVE_INF_POW
491 * The even/odd test in the if (this one and the one above) used to be ((long long) y % 2 == 0)
492 * on SPARC (long long) y for large y (>2**63) is always 0x7fffffff7fffffff, which
493 * is an odd number, so the test ((long long) y % 2 == 0) will always fail for
494 * large y. Since large double numbers are always even (e.g., the representation of
495 * 1E20+1 is the same as that of 1E20, the last .+1. is too insignificant to be part
496 * of the representation), this test will always return the wrong result for large y.
498 * The (ceil(y/2) == floor(y/2)) test is slower, but more robust.
500 if ((ret == PAL_NEGINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) == floor(y / 2)))
502 ret = PAL_POSINF_DBL; // +Inf
504 #endif // !HAVE_VALID_POSITIVE_INF_POW
506 LOGEXIT("pow returns double %f\n", ret);
517 PALIMPORT void __cdecl PAL_sincos(double x, double* sin, double* cos)
520 ENTRY("sincos (x=%f)\n", x);
522 #if defined(__APPLE__)
523 __sincos(x, sin, cos);
528 LOGEXIT("sincos returns (double %f, double %f)\n", *sin, *cos);
536 Determines whether given single-precision floating point value is finite.
540 _finitef returns a nonzero value (TRUE) if its argument x is not
541 infinite, that is, if -INF < x < +INF. It returns 0 (FALSE) if the
542 argument is infinite or a NaN.
546 x Single-precision floating-point value
549 int __cdecl _finitef(float x)
552 PERF_ENTRY(_finitef);
553 ENTRY("_finitef (x=%f)\n", x);
557 LOGEXIT("_finitef returns int %d\n", ret);
568 int __cdecl _isnanf(float x)
572 ENTRY("_isnanf (x=%f)\n", x);
576 LOGEXIT("_isnanf returns int %d\n", ret);
587 float __cdecl _copysignf(float x, float y)
590 PERF_ENTRY(_copysignf);
591 ENTRY("_copysignf (x=%f, y=%f)\n", x, y);
593 ret = copysign(x, y);
595 LOGEXIT("_copysignf returns float %f\n", ret);
596 PERF_EXIT(_copysignf);
606 PALIMPORT float __cdecl PAL_acosf(float x)
610 ENTRY("acosf (x=%f)\n", x);
612 #if !HAVE_COMPATIBLE_ACOS
614 #endif // HAVE_COMPATIBLE_ACOS
618 #if !HAVE_COMPATIBLE_ACOS
621 ret = PAL_NAN_FLT; // NaN
623 #endif // HAVE_COMPATIBLE_ACOS
625 LOGEXIT("acosf returns float %f\n", ret);
636 PALIMPORT float __cdecl PAL_acoshf(float x)
640 ENTRY("acoshf (x=%f)\n", x);
644 LOGEXIT("acoshf returns float %f\n", ret);
655 PALIMPORT float __cdecl PAL_asinf(float x)
659 ENTRY("asinf (x=%f)\n", x);
661 #if !HAVE_COMPATIBLE_ASIN
663 #endif // HAVE_COMPATIBLE_ASIN
667 #if !HAVE_COMPATIBLE_ASIN
670 ret = PAL_NAN_FLT; // NaN
672 #endif // HAVE_COMPATIBLE_ASIN
674 LOGEXIT("asinf returns float %f\n", ret);
685 PALIMPORT float __cdecl PAL_asinhf(float x)
689 ENTRY("asinhf (x=%f)\n", x);
693 LOGEXIT("asinhf returns float %f\n", ret);
705 PALIMPORT float __cdecl PAL_atan2f(float y, float x)
709 ENTRY("atan2f (y=%f, x=%f)\n", y, x);
711 #if !HAVE_COMPATIBLE_ATAN2
713 #endif // !HAVE_COMPATIBLE_ATAN2
717 #if !HAVE_COMPATIBLE_ATAN2
718 if ((errno == EDOM) && (x == 0.0f) && (y == 0.0f))
720 const float sign_x = copysign(1.0f, x);
721 const float sign_y = copysign(1.0f, y);
725 ret = copysign(0.0f, sign_y);
729 ret = copysign(atan2f(0.0f, -1.0f), sign_y);
732 #endif // !HAVE_COMPATIBLE_ATAN2
734 LOGEXIT("atan2f returns float %f\n", ret);
745 PALIMPORT float __cdecl PAL_expf(float x)
749 ENTRY("expf (x=%f)\n", x);
751 #if !HAVE_COMPATIBLE_EXP
758 #endif // HAVE_COMPATIBLE_EXP
762 #if !HAVE_COMPATIBLE_EXP
764 #endif // HAVE_COMPATIBLE_EXP
766 LOGEXIT("expf returns float %f\n", ret);
777 PALIMPORT float __cdecl PAL_fmaf(float x, float y, float z)
781 ENTRY("fmaf (x=%f, y=%f, z=%f)\n", x, y, z);
785 LOGEXIT("fma returns float %f\n", ret);
796 PALIMPORT int __cdecl PAL_ilogbf(float x)
800 ENTRY("ilogbf (x=%f)\n", x);
802 #if !HAVE_COMPATIBLE_ILOGB0
808 #endif // !HAVE_COMPATIBLE_ILOGB0
810 #if !HAVE_COMPATIBLE_ILOGBNAN
816 #endif // !HAVE_COMPATIBLE_ILOGBNAN
822 LOGEXIT("ilogbf returns int %d\n", ret);
833 PALIMPORT float __cdecl PAL_logf(float x)
837 ENTRY("logf (x=%f)\n", x);
839 #if !HAVE_COMPATIBLE_LOG
841 #endif // !HAVE_COMPATIBLE_LOG
845 #if !HAVE_COMPATIBLE_LOG
846 if ((errno == EDOM) && (x < 0))
848 ret = PAL_NAN_FLT; // NaN
850 #endif // !HAVE_COMPATIBLE_LOG
852 LOGEXIT("logf returns float %f\n", ret);
863 PALIMPORT float __cdecl PAL_log2f(float x)
867 ENTRY("log2f (x=%f)\n", x);
871 LOGEXIT("log2f returns float %f\n", ret);
882 PALIMPORT float __cdecl PAL_log10f(float x)
886 ENTRY("log10f (x=%f)\n", x);
888 #if !HAVE_COMPATIBLE_LOG10
890 #endif // !HAVE_COMPATIBLE_LOG10
894 #if !HAVE_COMPATIBLE_LOG10
895 if ((errno == EDOM) && (x < 0))
897 ret = PAL_NAN_FLT; // NaN
899 #endif // !HAVE_COMPATIBLE_LOG10
901 LOGEXIT("log10f returns float %f\n", ret);
912 PALIMPORT float __cdecl PAL_powf(float x, float y)
916 ENTRY("powf (x=%f, y=%f)\n", x, y);
918 #if !HAVE_COMPATIBLE_POW
919 if ((y == PAL_POSINF_FLT) && !isnan(x)) // +Inf
929 else if ((x > -1.0f) && (x < 1.0f))
935 ret = PAL_POSINF_FLT; // +Inf
938 else if ((y == PAL_NEGINF_FLT) && !isnan(x)) // -Inf
948 else if ((x > -1.0f) && (x < 1.0f))
950 ret = PAL_POSINF_FLT; // +Inf
957 else if (IS_FLT_NEGZERO(x) && (y == -1.0f))
959 ret = PAL_NEGINF_FLT; // -Inf
961 else if ((x == 0.0f) && (y < 0.0f))
963 ret = PAL_POSINF_FLT; // +Inf
966 #endif // !HAVE_COMPATIBLE_POW
970 #if !HAVE_VALID_NEGATIVE_INF_POW
971 if ((ret == PAL_POSINF_FLT) && (x < 0) && isfinite(x) && (ceilf(y / 2) != floorf(y / 2)))
973 ret = PAL_NEGINF_FLT; // -Inf
975 #endif // !HAVE_VALID_NEGATIVE_INF_POW
977 #if !HAVE_VALID_POSITIVE_INF_POW
979 * The (ceil(y/2) == floor(y/2)) test is slower, but more robust for platforms where large y
980 * will return the wrong result for ((long) y % 2 == 0). See PAL_pow(double) above for more details.
982 if ((ret == PAL_NEGINF_FLT) && (x < 0) && isfinite(x) && (ceilf(y / 2) == floorf(y / 2)))
984 ret = PAL_POSINF_FLT; // +Inf
986 #endif // !HAVE_VALID_POSITIVE_INF_POW
988 LOGEXIT("powf returns float %f\n", ret);
999 PALIMPORT void __cdecl PAL_sincosf(float x, float* sin, float* cos)
1001 PERF_ENTRY(sincosf);
1002 ENTRY("sincosf (x=%f)\n", x);
1004 #if defined(__APPLE__)
1005 __sincosf(x, sin, cos);
1007 sincosf(x, sin, cos);
1008 #endif // !__APPLE__
1010 LOGEXIT("sincosf returns (float %f, float %f)\n", *sin, *cos);