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.
4
5/*++
6
7
8
9Module Name:
10
11 math.cpp
12
13Abstract:
14
15 Implementation of math family functions.
16
17
18
19--*/
20
21#include "pal/palinternal.h"
22#include "pal/dbgmsg.h"
23
24#include <math.h>
25
26#if HAVE_IEEEFP_H
27#include <ieeefp.h>
28#endif // HAVE_IEEEFP_H
29
30#include <errno.h>
31
32#define PAL_NAN_DBL sqrt(-1.0)
33#define PAL_POSINF_DBL -log(0.0)
34#define PAL_NEGINF_DBL log(0.0)
35
36#define IS_DBL_NEGZERO(x) (((*((INT64*)((void*)&x))) & I64(0xFFFFFFFFFFFFFFFF)) == I64(0x8000000000000000))
37
38#define PAL_NAN_FLT sqrtf(-1.0f)
39#define PAL_POSINF_FLT -logf(0.0f)
40#define PAL_NEGINF_FLT logf(0.0f)
41
42#define IS_FLT_NEGZERO(x) (((*((INT32*)((void*)&x))) & 0xFFFFFFFF) == 0x80000000)
43
44SET_DEFAULT_DEBUG_CHANNEL(CRT);
45
46/*++
47Function:
48 _signbit
49
50Determines whether given double-precision floating point value has a negative sign.
51
52Return Value
53
54_signbit returns a nonzero value (TRUE) if the sign of its argument x is negative.
55
56Parameter
57
58x Double-precision floating-point value
59
60--*/
61int __cdecl _signbit(double x)
62{
63 int ret;
64 PERF_ENTRY(_signbit);
65 ENTRY("_signbit (x=%f)\n", x);
66
67 ret = signbit(x);
68
69 LOGEXIT("_signbit returns int %d\n", ret);
70 PERF_EXIT(_signbit);
71 return ret;
72}
73
74/*++
75Function:
76 _finite
77
78Determines whether given double-precision floating point value is finite.
79
80Return Value
81
82_finite returns a nonzero value (TRUE) if its argument x is not
83infinite, that is, if -INF < x < +INF. It returns 0 (FALSE) if the
84argument is infinite or a NaN.
85
86Parameter
87
88x Double-precision floating-point value
89
90--*/
91int __cdecl _finite(double x)
92{
93 int ret;
94 PERF_ENTRY(_finite);
95 ENTRY("_finite (x=%f)\n", x);
96
97 ret = isfinite(x);
98
99 LOGEXIT("_finite returns int %d\n", ret);
100 PERF_EXIT(_finite);
101 return ret;
102}
103
104/*++
105Function:
106 _isnan
107
108See MSDN doc
109--*/
110int __cdecl _isnan(double x)
111{
112 int ret;
113 PERF_ENTRY(_isnan);
114 ENTRY("_isnan (x=%f)\n", x);
115
116 ret = isnan(x);
117
118 LOGEXIT("_isnan returns int %d\n", ret);
119 PERF_EXIT(_isnan);
120 return ret;
121}
122
123/*++
124Function:
125 _copysign
126
127See MSDN doc
128--*/
129double __cdecl _copysign(double x, double y)
130{
131 double ret;
132 PERF_ENTRY(_copysign);
133 ENTRY("_copysign (x=%f, y=%f)\n", x, y);
134
135 ret = copysign(x, y);
136
137 LOGEXIT("_copysign returns double %f\n", ret);
138 PERF_EXIT(_copysign);
139 return ret;
140}
141
142/*++
143Function:
144 acos
145
146See MSDN.
147--*/
148PALIMPORT double __cdecl PAL_acos(double x)
149{
150 double ret;
151 PERF_ENTRY(acos);
152 ENTRY("acos (x=%f)\n", x);
153
154#if !HAVE_COMPATIBLE_ACOS
155 errno = 0;
156#endif // HAVE_COMPATIBLE_ACOS
157
158 ret = acos(x);
159
160#if !HAVE_COMPATIBLE_ACOS
161 if (errno == EDOM)
162 {
163 ret = PAL_NAN_DBL; // NaN
164 }
165#endif // HAVE_COMPATIBLE_ACOS
166
167 LOGEXIT("acos returns double %f\n", ret);
168 PERF_EXIT(acos);
169 return ret;
170}
171
172/*++
173Function:
174 acosh
175
176See MSDN.
177--*/
178PALIMPORT double __cdecl PAL_acosh(double x)
179{
180 double ret;
181 PERF_ENTRY(acosh);
182 ENTRY("acosh (x=%f)\n", x);
183
184 ret = acosh(x);
185
186 LOGEXIT("acosh returns double %f\n", ret);
187 PERF_EXIT(acosh);
188 return ret;
189}
190
191/*++
192Function:
193 asin
194
195See MSDN.
196--*/
197PALIMPORT double __cdecl PAL_asin(double x)
198{
199 double ret;
200 PERF_ENTRY(asin);
201 ENTRY("asin (x=%f)\n", x);
202
203#if !HAVE_COMPATIBLE_ASIN
204 errno = 0;
205#endif // HAVE_COMPATIBLE_ASIN
206
207 ret = asin(x);
208
209#if !HAVE_COMPATIBLE_ASIN
210 if (errno == EDOM)
211 {
212 ret = PAL_NAN_DBL; // NaN
213 }
214#endif // HAVE_COMPATIBLE_ASIN
215
216 LOGEXIT("asin returns double %f\n", ret);
217 PERF_EXIT(asin);
218 return ret;
219}
220
221/*++
222Function:
223 asinh
224
225See MSDN.
226--*/
227PALIMPORT double __cdecl PAL_asinh(double x)
228{
229 double ret;
230 PERF_ENTRY(asinh);
231 ENTRY("asinh (x=%f)\n", x);
232
233 ret = asinh(x);
234
235 LOGEXIT("asinh returns double %f\n", ret);
236 PERF_EXIT(asinh);
237 return ret;
238}
239
240/*++
241Function:
242 atan2
243
244See MSDN.
245--*/
246PALIMPORT double __cdecl PAL_atan2(double y, double x)
247{
248 double ret;
249 PERF_ENTRY(atan2);
250 ENTRY("atan2 (y=%f, x=%f)\n", y, x);
251
252#if !HAVE_COMPATIBLE_ATAN2
253 errno = 0;
254#endif // !HAVE_COMPATIBLE_ATAN2
255
256 ret = atan2(y, x);
257
258#if !HAVE_COMPATIBLE_ATAN2
259 if ((errno == EDOM) && (x == 0.0) && (y == 0.0))
260 {
261 const double sign_x = copysign(1.0, x);
262 const double sign_y = copysign(1.0, y);
263
264 if (sign_x > 0)
265 {
266 ret = copysign(0.0, sign_y);
267 }
268 else
269 {
270 ret = copysign(atan2(0.0, -1.0), sign_y);
271 }
272 }
273#endif // !HAVE_COMPATIBLE_ATAN2
274
275 LOGEXIT("atan2 returns double %f\n", ret);
276 PERF_EXIT(atan2);
277 return ret;
278}
279
280/*++
281Function:
282 exp
283
284See MSDN.
285--*/
286PALIMPORT double __cdecl PAL_exp(double x)
287{
288 double ret;
289 PERF_ENTRY(exp);
290 ENTRY("exp (x=%f)\n", x);
291
292#if !HAVE_COMPATIBLE_EXP
293 if (x == 1.0)
294 {
295 ret = M_E;
296 }
297 else
298 {
299#endif // HAVE_COMPATIBLE_EXP
300
301 ret = exp(x);
302
303#if !HAVE_COMPATIBLE_EXP
304 }
305#endif // HAVE_COMPATIBLE_EXP
306
307 LOGEXIT("exp returns double %f\n", ret);
308 PERF_EXIT(exp);
309 return ret;
310}
311
312/*++
313Function:
314 fma
315
316See MSDN.
317--*/
318PALIMPORT double __cdecl PAL_fma(double x, double y, double z)
319{
320 double ret;
321 PERF_ENTRY(fma);
322 ENTRY("fma (x=%f, y=%f, z=%f)\n", x, y, z);
323
324 ret = fma(x, y, z);
325
326 LOGEXIT("fma returns double %f\n", ret);
327 PERF_EXIT(fma);
328 return ret;
329}
330
331/*++
332Function:
333 ilogb
334
335See MSDN.
336--*/
337PALIMPORT int __cdecl PAL_ilogb(double x)
338{
339 int ret;
340 PERF_ENTRY(ilogb);
341 ENTRY("ilogb (x=%f)\n", x);
342
343#if !HAVE_COMPATIBLE_ILOGB0
344 if (x == 0.0)
345 {
346 ret = -2147483648;
347 }
348 else
349#endif // !HAVE_COMPATIBLE_ILOGB0
350
351#if !HAVE_COMPATIBLE_ILOGBNAN
352 if (isnan(x))
353 {
354 ret = 2147483647;
355 }
356 else
357#endif // !HAVE_COMPATIBLE_ILOGBNAN
358
359 {
360 ret = ilogb(x);
361 }
362
363 LOGEXIT("ilogb returns int %d\n", ret);
364 PERF_EXIT(ilogb);
365 return ret;
366}
367
368/*++
369Function:
370 labs
371
372See MSDN.
373--*/
374PALIMPORT LONG __cdecl PAL_labs(LONG l)
375{
376 long lRet;
377 PERF_ENTRY(labs);
378 ENTRY("labs (l=%ld)\n", l);
379
380 lRet = labs(l);
381
382 LOGEXIT("labs returns long %ld\n", lRet);
383 PERF_EXIT(labs);
384 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.
385}
386
387/*++
388Function:
389 log
390
391See MSDN.
392--*/
393PALIMPORT double __cdecl PAL_log(double x)
394{
395 double ret;
396 PERF_ENTRY(log);
397 ENTRY("log (x=%f)\n", x);
398
399#if !HAVE_COMPATIBLE_LOG
400 errno = 0;
401#endif // !HAVE_COMPATIBLE_LOG
402
403 ret = log(x);
404
405#if !HAVE_COMPATIBLE_LOG
406 if ((errno == EDOM) && (x < 0))
407 {
408 ret = PAL_NAN_DBL; // NaN
409 }
410#endif // !HAVE_COMPATIBLE_LOG
411
412 LOGEXIT("log returns double %f\n", ret);
413 PERF_EXIT(log);
414 return ret;
415}
416
417/*++
418Function:
419 log2
420
421See MSDN.
422--*/
423PALIMPORT double __cdecl PAL_log2(double x)
424{
425 double ret;
426 PERF_ENTRY(log2);
427 ENTRY("log2 (x=%f)\n", x);
428
429 ret = log2(x);
430
431 LOGEXIT("log2 returns double %f\n", ret);
432 PERF_EXIT(log2);
433 return ret;
434}
435
436/*++
437Function:
438 log10
439
440See MSDN.
441--*/
442PALIMPORT double __cdecl PAL_log10(double x)
443{
444 double ret;
445 PERF_ENTRY(log10);
446 ENTRY("log10 (x=%f)\n", x);
447
448#if !HAVE_COMPATIBLE_LOG10
449 errno = 0;
450#endif // !HAVE_COMPATIBLE_LOG10
451
452 ret = log10(x);
453
454#if !HAVE_COMPATIBLE_LOG10
455 if ((errno == EDOM) && (x < 0))
456 {
457 ret = PAL_NAN_DBL; // NaN
458 }
459#endif // !HAVE_COMPATIBLE_LOG10
460
461 LOGEXIT("log10 returns double %f\n", ret);
462 PERF_EXIT(log10);
463 return ret;
464}
465
466/*++
467Function:
468 pow
469
470See MSDN.
471--*/
472PALIMPORT double __cdecl PAL_pow(double x, double y)
473{
474 double ret;
475 PERF_ENTRY(pow);
476 ENTRY("pow (x=%f, y=%f)\n", x, y);
477
478#if !HAVE_COMPATIBLE_POW
479 if ((y == PAL_POSINF_DBL) && !isnan(x)) // +Inf
480 {
481 if (x == 1.0)
482 {
483 ret = x;
484 }
485 else if (x == -1.0)
486 {
487 ret = 1.0;
488 }
489 else if ((x > -1.0) && (x < 1.0))
490 {
491 ret = 0.0;
492 }
493 else
494 {
495 ret = PAL_POSINF_DBL; // +Inf
496 }
497 }
498 else if ((y == PAL_NEGINF_DBL) && !isnan(x)) // -Inf
499 {
500 if (x == 1.0)
501 {
502 ret = x;
503 }
504 else if (x == -1.0)
505 {
506 ret = 1.0;
507 }
508 else if ((x > -1.0) && (x < 1.0))
509 {
510 ret = PAL_POSINF_DBL; // +Inf
511 }
512 else
513 {
514 ret = 0.0;
515 }
516 }
517 else if (IS_DBL_NEGZERO(x) && (y == -1.0))
518 {
519 ret = PAL_NEGINF_DBL; // -Inf
520 }
521 else if ((x == 0.0) && (y < 0.0))
522 {
523 ret = PAL_POSINF_DBL; // +Inf
524 }
525 else
526#endif // !HAVE_COMPATIBLE_POW
527
528 ret = pow(x, y);
529
530#if !HAVE_VALID_NEGATIVE_INF_POW
531 if ((ret == PAL_POSINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) != floor(y / 2)))
532 {
533 ret = PAL_NEGINF_DBL; // -Inf
534 }
535#endif // !HAVE_VALID_NEGATIVE_INF_POW
536
537#if !HAVE_VALID_POSITIVE_INF_POW
538 /*
539 * The even/odd test in the if (this one and the one above) used to be ((long long) y % 2 == 0)
540 * on SPARC (long long) y for large y (>2**63) is always 0x7fffffff7fffffff, which
541 * is an odd number, so the test ((long long) y % 2 == 0) will always fail for
542 * large y. Since large double numbers are always even (e.g., the representation of
543 * 1E20+1 is the same as that of 1E20, the last .+1. is too insignificant to be part
544 * of the representation), this test will always return the wrong result for large y.
545 *
546 * The (ceil(y/2) == floor(y/2)) test is slower, but more robust.
547 */
548 if ((ret == PAL_NEGINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) == floor(y / 2)))
549 {
550 ret = PAL_POSINF_DBL; // +Inf
551 }
552#endif // !HAVE_VALID_POSITIVE_INF_POW
553
554 LOGEXIT("pow returns double %f\n", ret);
555 PERF_EXIT(pow);
556 return ret;
557}
558
559/*++
560Function:
561 scalbn
562
563See MSDN.
564--*/
565PALIMPORT double __cdecl PAL_scalbn(double x, int n)
566{
567 double ret;
568 PERF_ENTRY(scalbn);
569 ENTRY("scalbn (x=%f, n=%d)\n", x, n);
570
571 ret = scalbn(x, n);
572
573 LOGEXIT("scalbn returns double %f\n", ret);
574 PERF_EXIT(scalbn);
575 return ret;
576}
577
578/*++
579Function:
580 _signbitf
581
582Determines whether given single-precision floating point value has a negative sign.
583
584Return Value
585
586_signbitf returns a nonzero value (TRUE) if the sign of its argument x is negative.
587
588Parameter
589
590x Single-precision floating-point value
591
592--*/
593int __cdecl _signbitf(float x)
594{
595 int ret;
596 PERF_ENTRY(_signbitf);
597 ENTRY("_signbitf (x=%f)\n", x);
598
599 ret = signbit(x);
600
601 LOGEXIT("_signbitf returns int %d\n", ret);
602 PERF_EXIT(_signbitf);
603 return ret;
604}
605
606/*++
607Function:
608 _finitef
609
610Determines whether given single-precision floating point value is finite.
611
612Return Value
613
614_finitef returns a nonzero value (TRUE) if its argument x is not
615infinite, that is, if -INF < x < +INF. It returns 0 (FALSE) if the
616argument is infinite or a NaN.
617
618Parameter
619
620x Single-precision floating-point value
621
622--*/
623int __cdecl _finitef(float x)
624{
625 int ret;
626 PERF_ENTRY(_finitef);
627 ENTRY("_finitef (x=%f)\n", x);
628
629 ret = isfinite(x);
630
631 LOGEXIT("_finitef returns int %d\n", ret);
632 PERF_EXIT(_finitef);
633 return ret;
634}
635
636/*++
637Function:
638 _isnanf
639
640See MSDN doc
641--*/
642int __cdecl _isnanf(float x)
643{
644 int ret;
645 PERF_ENTRY(_isnanf);
646 ENTRY("_isnanf (x=%f)\n", x);
647
648 ret = isnan(x);
649
650 LOGEXIT("_isnanf returns int %d\n", ret);
651 PERF_EXIT(_isnanf);
652 return ret;
653}
654
655/*++
656Function:
657 _copysignf
658
659See MSDN doc
660--*/
661float __cdecl _copysignf(float x, float y)
662{
663 float ret;
664 PERF_ENTRY(_copysignf);
665 ENTRY("_copysignf (x=%f, y=%f)\n", x, y);
666
667 ret = copysign(x, y);
668
669 LOGEXIT("_copysignf returns float %f\n", ret);
670 PERF_EXIT(_copysignf);
671 return ret;
672}
673
674/*++
675Function:
676 acosf
677
678See MSDN.
679--*/
680PALIMPORT float __cdecl PAL_acosf(float x)
681{
682 float ret;
683 PERF_ENTRY(acosf);
684 ENTRY("acosf (x=%f)\n", x);
685
686#if !HAVE_COMPATIBLE_ACOS
687 errno = 0;
688#endif // HAVE_COMPATIBLE_ACOS
689
690 ret = acosf(x);
691
692#if !HAVE_COMPATIBLE_ACOS
693 if (errno == EDOM)
694 {
695 ret = PAL_NAN_FLT; // NaN
696 }
697#endif // HAVE_COMPATIBLE_ACOS
698
699 LOGEXIT("acosf returns float %f\n", ret);
700 PERF_EXIT(acosf);
701 return ret;
702}
703
704/*++
705Function:
706 acoshf
707
708See MSDN.
709--*/
710PALIMPORT float __cdecl PAL_acoshf(float x)
711{
712 float ret;
713 PERF_ENTRY(acoshf);
714 ENTRY("acoshf (x=%f)\n", x);
715
716 ret = acoshf(x);
717
718 LOGEXIT("acoshf returns float %f\n", ret);
719 PERF_EXIT(acoshf);
720 return ret;
721}
722
723/*++
724Function:
725 asinf
726
727See MSDN.
728--*/
729PALIMPORT float __cdecl PAL_asinf(float x)
730{
731 float ret;
732 PERF_ENTRY(asinf);
733 ENTRY("asinf (x=%f)\n", x);
734
735#if !HAVE_COMPATIBLE_ASIN
736 errno = 0;
737#endif // HAVE_COMPATIBLE_ASIN
738
739 ret = asinf(x);
740
741#if !HAVE_COMPATIBLE_ASIN
742 if (errno == EDOM)
743 {
744 ret = PAL_NAN_FLT; // NaN
745 }
746#endif // HAVE_COMPATIBLE_ASIN
747
748 LOGEXIT("asinf returns float %f\n", ret);
749 PERF_EXIT(asinf);
750 return ret;
751}
752
753/*++
754Function:
755 asinhf
756
757See MSDN.
758--*/
759PALIMPORT float __cdecl PAL_asinhf(float x)
760{
761 float ret;
762 PERF_ENTRY(asinhf);
763 ENTRY("asinhf (x=%f)\n", x);
764
765 ret = asinhf(x);
766
767 LOGEXIT("asinhf returns float %f\n", ret);
768 PERF_EXIT(asinhf);
769 return ret;
770}
771
772
773/*++
774Function:
775 atan2f
776
777See MSDN.
778--*/
779PALIMPORT float __cdecl PAL_atan2f(float y, float x)
780{
781 float ret;
782 PERF_ENTRY(atan2f);
783 ENTRY("atan2f (y=%f, x=%f)\n", y, x);
784
785#if !HAVE_COMPATIBLE_ATAN2
786 errno = 0;
787#endif // !HAVE_COMPATIBLE_ATAN2
788
789 ret = atan2f(y, x);
790
791#if !HAVE_COMPATIBLE_ATAN2
792 if ((errno == EDOM) && (x == 0.0f) && (y == 0.0f))
793 {
794 const float sign_x = copysign(1.0f, x);
795 const float sign_y = copysign(1.0f, y);
796
797 if (sign_x > 0)
798 {
799 ret = copysign(0.0f, sign_y);
800 }
801 else
802 {
803 ret = copysign(atan2f(0.0f, -1.0f), sign_y);
804 }
805 }
806#endif // !HAVE_COMPATIBLE_ATAN2
807
808 LOGEXIT("atan2f returns float %f\n", ret);
809 PERF_EXIT(atan2f);
810 return ret;
811}
812
813/*++
814Function:
815 expf
816
817See MSDN.
818--*/
819PALIMPORT float __cdecl PAL_expf(float x)
820{
821 float ret;
822 PERF_ENTRY(expf);
823 ENTRY("expf (x=%f)\n", x);
824
825#if !HAVE_COMPATIBLE_EXP
826 if (x == 1.0f)
827 {
828 ret = M_E;
829 }
830 else
831 {
832#endif // HAVE_COMPATIBLE_EXP
833
834 ret = expf(x);
835
836#if !HAVE_COMPATIBLE_EXP
837 }
838#endif // HAVE_COMPATIBLE_EXP
839
840 LOGEXIT("expf returns float %f\n", ret);
841 PERF_EXIT(expf);
842 return ret;
843}
844
845/*++
846Function:
847 fmaf
848
849See MSDN.
850--*/
851PALIMPORT float __cdecl PAL_fmaf(float x, float y, float z)
852{
853 float ret;
854 PERF_ENTRY(fmaf);
855 ENTRY("fmaf (x=%f, y=%f, z=%f)\n", x, y, z);
856
857 ret = fmaf(x, y, z);
858
859 LOGEXIT("fma returns float %f\n", ret);
860 PERF_EXIT(fmaf);
861 return ret;
862}
863
864/*++
865Function:
866 ilogbf
867
868See MSDN.
869--*/
870PALIMPORT int __cdecl PAL_ilogbf(float x)
871{
872 int ret;
873 PERF_ENTRY(ilogbf);
874 ENTRY("ilogbf (x=%f)\n", x);
875
876#if !HAVE_COMPATIBLE_ILOGB0
877 if (x == 0.0f)
878 {
879 ret = -2147483648;
880 }
881 else
882#endif // !HAVE_COMPATIBLE_ILOGB0
883
884#if !HAVE_COMPATIBLE_ILOGBNAN
885 if (isnan(x))
886 {
887 ret = 2147483647;
888 }
889 else
890#endif // !HAVE_COMPATIBLE_ILOGBNAN
891
892 {
893 ret = ilogbf(x);
894 }
895
896 LOGEXIT("ilogbf returns int %d\n", ret);
897 PERF_EXIT(ilogbf);
898 return ret;
899}
900
901/*++
902Function:
903 logf
904
905See MSDN.
906--*/
907PALIMPORT float __cdecl PAL_logf(float x)
908{
909 float ret;
910 PERF_ENTRY(logf);
911 ENTRY("logf (x=%f)\n", x);
912
913#if !HAVE_COMPATIBLE_LOG
914 errno = 0;
915#endif // !HAVE_COMPATIBLE_LOG
916
917 ret = logf(x);
918
919#if !HAVE_COMPATIBLE_LOG
920 if ((errno == EDOM) && (x < 0))
921 {
922 ret = PAL_NAN_FLT; // NaN
923 }
924#endif // !HAVE_COMPATIBLE_LOG
925
926 LOGEXIT("logf returns float %f\n", ret);
927 PERF_EXIT(logf);
928 return ret;
929}
930
931/*++
932Function:
933 log2f
934
935See MSDN.
936--*/
937PALIMPORT float __cdecl PAL_log2f(float x)
938{
939 float ret;
940 PERF_ENTRY(log2f);
941 ENTRY("log2f (x=%f)\n", x);
942
943 ret = log2f(x);
944
945 LOGEXIT("log2f returns float %f\n", ret);
946 PERF_EXIT(log2f);
947 return ret;
948}
949
950/*++
951Function:
952 log10f
953
954See MSDN.
955--*/
956PALIMPORT float __cdecl PAL_log10f(float x)
957{
958 float ret;
959 PERF_ENTRY(log10f);
960 ENTRY("log10f (x=%f)\n", x);
961
962#if !HAVE_COMPATIBLE_LOG10
963 errno = 0;
964#endif // !HAVE_COMPATIBLE_LOG10
965
966 ret = log10f(x);
967
968#if !HAVE_COMPATIBLE_LOG10
969 if ((errno == EDOM) && (x < 0))
970 {
971 ret = PAL_NAN_FLT; // NaN
972 }
973#endif // !HAVE_COMPATIBLE_LOG10
974
975 LOGEXIT("log10f returns float %f\n", ret);
976 PERF_EXIT(log10f);
977 return ret;
978}
979
980/*++
981Function:
982 powf
983
984See MSDN.
985--*/
986PALIMPORT float __cdecl PAL_powf(float x, float y)
987{
988 float ret;
989 PERF_ENTRY(powf);
990 ENTRY("powf (x=%f, y=%f)\n", x, y);
991
992#if !HAVE_COMPATIBLE_POW
993 if ((y == PAL_POSINF_FLT) && !isnan(x)) // +Inf
994 {
995 if (x == 1.0f)
996 {
997 ret = x;
998 }
999 else if (x == -1.0f)
1000 {
1001 ret = 1.0f;
1002 }
1003 else if ((x > -1.0f) && (x < 1.0f))
1004 {
1005 ret = 0.0f;
1006 }
1007 else
1008 {
1009 ret = PAL_POSINF_FLT; // +Inf
1010 }
1011 }
1012 else if ((y == PAL_NEGINF_FLT) && !isnan(x)) // -Inf
1013 {
1014 if (x == 1.0f)
1015 {
1016 ret = x;
1017 }
1018 else if (x == -1.0f)
1019 {
1020 ret = 1.0f;
1021 }
1022 else if ((x > -1.0f) && (x < 1.0f))
1023 {
1024 ret = PAL_POSINF_FLT; // +Inf
1025 }
1026 else
1027 {
1028 ret = 0.0f;
1029 }
1030 }
1031 else if (IS_FLT_NEGZERO(x) && (y == -1.0f))
1032 {
1033 ret = PAL_NEGINF_FLT; // -Inf
1034 }
1035 else if ((x == 0.0f) && (y < 0.0f))
1036 {
1037 ret = PAL_POSINF_FLT; // +Inf
1038 }
1039 else
1040#endif // !HAVE_COMPATIBLE_POW
1041
1042 ret = powf(x, y);
1043
1044#if !HAVE_VALID_NEGATIVE_INF_POW
1045 if ((ret == PAL_POSINF_FLT) && (x < 0) && isfinite(x) && (ceilf(y / 2) != floorf(y / 2)))
1046 {
1047 ret = PAL_NEGINF_FLT; // -Inf
1048 }
1049#endif // !HAVE_VALID_NEGATIVE_INF_POW
1050
1051#if !HAVE_VALID_POSITIVE_INF_POW
1052 /*
1053 * The (ceil(y/2) == floor(y/2)) test is slower, but more robust for platforms where large y
1054 * will return the wrong result for ((long) y % 2 == 0). See PAL_pow(double) above for more details.
1055 */
1056 if ((ret == PAL_NEGINF_FLT) && (x < 0) && isfinite(x) && (ceilf(y / 2) == floorf(y / 2)))
1057 {
1058 ret = PAL_POSINF_FLT; // +Inf
1059 }
1060#endif // !HAVE_VALID_POSITIVE_INF_POW
1061
1062 LOGEXIT("powf returns float %f\n", ret);
1063 PERF_EXIT(powf);
1064 return ret;
1065}
1066
1067/*++
1068Function:
1069 scalbnf
1070
1071See MSDN.
1072--*/
1073PALIMPORT float __cdecl PAL_scalbnf(float x, int n)
1074{
1075 float ret;
1076 PERF_ENTRY(scalbnf);
1077 ENTRY("scalbnf (x=%f, n=%d)\n", x, n);
1078
1079 ret = scalbnf(x, n);
1080
1081 LOGEXIT("scalbnf returns double %f\n", ret);
1082 PERF_EXIT(scalbnf);
1083 return ret;
1084}
1085