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** Source: test1.c
8**
9** Purpose: Test to ensure that fmod return the correct values
10**
11** Dependencies: PAL_Initialize
12** PAL_Terminate
13** Fail
14** fabs
15**
16**===========================================================================*/
17
18#include <palsuite.h>
19
20// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
21// is slightly too accurate when writing tests meant to run against libm implementations
22// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
23//
24// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
25// so that the delta used for comparison will compare the most significant digits and ignore
26// any digits that are outside the double precision range (15-17 digits).
27
28// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
29// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
30// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
31// use PAL_EPSILON * 10.
32#define PAL_EPSILON 8.8817841970012523e-16
33
34#define PAL_NAN sqrt(-1.0)
35#define PAL_POSINF -log(0.0)
36#define PAL_NEGINF log(0.0)
37
38/**
39 * Helper test structure
40 */
41struct test
42{
43 double numerator; /* second component of the value to test the function with */
44 double denominator; /* first component of the value to test the function with */
45 double expected; /* expected result */
46 double variance; /* maximum delta between the expected and actual result */
47};
48
49/**
50 * validate
51 *
52 * test validation function
53 */
54void __cdecl validate(double numerator, double denominator, double expected, double variance)
55{
56 double result = fmod(numerator, denominator);
57
58 /*
59 * The test is valid when the difference between result
60 * and expected is less than or equal to variance
61 */
62 double delta = fabs(result - expected);
63
64 if (delta > variance)
65 {
66 Fail("fmod(%g, %g) returned %20.17g when it should have returned %20.17g",
67 numerator, denominator, result, expected);
68 }
69}
70
71/**
72 * validate
73 *
74 * test validation function for values returning NaN
75 */
76void __cdecl validate_isnan(double numerator, double denominator)
77{
78 double result = fmod(numerator, denominator);
79
80 if (!_isnan(result))
81 {
82 Fail("fmod(%g, %g) returned %20.17g when it should have returned %20.17g",
83 numerator, denominator, result, PAL_NAN);
84 }
85}
86
87/**
88 * main
89 *
90 * executable entry point
91 */
92INT __cdecl main(INT argc, CHAR **argv)
93{
94 struct test tests[] =
95 {
96 /* numerator denominator expected variance */
97 { 0, PAL_POSINF, 0, PAL_EPSILON },
98 { 0.31296179620778659, 0.94976571538163866, 0.31296179620778658, PAL_EPSILON },
99 { 0.42077048331375735, 0.90716712923909839, 0.42077048331375733, PAL_EPSILON },
100 { 0.59448076852482208, 0.80410982822879171, 0.59448076852482212, PAL_EPSILON },
101 { 0.63896127631363480, 0.76923890136397213, 0.63896127631363475, PAL_EPSILON },
102 { 0.64963693908006244, 0.76024459707563015, 0.64963693908006248, PAL_EPSILON },
103 { 0.70710678118654752, 0.70710678118654752, 0, PAL_EPSILON },
104 { 1, 1, 0, PAL_EPSILON },
105 { 0.84147098480789651, 0.54030230586813972, 0.30116867893975674, PAL_EPSILON },
106 { 0.90371945743584630, 0.42812514788535792, 0.047469161665130377, PAL_EPSILON / 10 },
107 { 0.98776594599273553, 0.15594369476537447, 0.052103777400488605, PAL_EPSILON / 10 },
108 { 0.99180624439366372, 0.12775121753523991, 0.097547721646984359, PAL_EPSILON / 10 },
109 { 0.74398033695749319, -0.66820151019031295, 0.075778826767180285, PAL_EPSILON / 10 },
110 { 0.41078129050290870, -0.91173391478696510, 0.41078129050290868, PAL_EPSILON },
111 { 0, -1, 0, PAL_EPSILON },
112 { 1, PAL_POSINF, 1, PAL_EPSILON * 10 },
113 };
114
115
116 // PAL initialization
117 if (PAL_Initialize(argc, argv) != 0)
118 {
119 return FAIL;
120 }
121
122 for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
123 {
124 validate( tests[i].numerator, tests[i].denominator, tests[i].expected, tests[i].variance);
125 validate(-tests[i].numerator, tests[i].denominator, -tests[i].expected, tests[i].variance);
126 validate( tests[i].numerator, -tests[i].denominator, tests[i].expected, tests[i].variance);
127 validate(-tests[i].numerator, -tests[i].denominator, -tests[i].expected, tests[i].variance);
128 }
129
130 validate_isnan( 0, 0);
131 validate_isnan(-0.0, 0);
132 validate_isnan( 0, -0.0);
133 validate_isnan(-0.0, -0.0);
134
135 validate_isnan( 1, 0);
136 validate_isnan(-1.0, 0);
137 validate_isnan( 1, -0.0);
138 validate_isnan(-1.0, -0.0);
139
140 validate_isnan(PAL_POSINF, PAL_POSINF);
141 validate_isnan(PAL_NEGINF, PAL_POSINF);
142 validate_isnan(PAL_POSINF, PAL_NEGINF);
143 validate_isnan(PAL_NEGINF, PAL_NEGINF);
144
145 validate_isnan(PAL_POSINF, 0);
146 validate_isnan(PAL_NEGINF, 0);
147 validate_isnan(PAL_POSINF, -0.0);
148 validate_isnan(PAL_NEGINF, -0.0);
149
150 validate_isnan(PAL_POSINF, 1);
151 validate_isnan(PAL_NEGINF, 1);
152 validate_isnan(PAL_POSINF, -1.0);
153 validate_isnan(PAL_NEGINF, -1.0);
154
155 PAL_Terminate();
156 return PASS;
157}
158