1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <assert.h>
20 #include <math.h>
21 #include <fenv.h>
22
23 #define ASSERT_TRUE(condition) \
24 (condition)? (void)0 : fail(__FILE__, __LINE__, __func__, #condition)
25
26 #define ASSERT_EQ(x, y) \
27 ((x)==(y))? (void)0 : fail(__FILE__, __LINE__, __func__, #x "==" #y)
28
29 #define ASSERT_FLOAT_EQ(x, y) \
30 float_eq(x, y)? (void)0 : fail(__FILE__, __LINE__, __func__, "float_eq(" #x "," #y ")")
31
32 #define TEST(f, g) void g()
33
34 int total_fail = 0;
fail(const char * file,int line,const char * func,const char * expr)35 void fail(const char* file, int line, const char* func, const char* expr)
36 {
37 printf("ERROR %s:%d %s: %s\n", file, line, func, expr);
38 total_fail++;
39 }
40
41 /* See AOSP external/gtest/include/gtest/internal/gtest-internal.h */
42 const int kMaxUlps = 4;
43
float_eq(float x,float y)44 int float_eq(float x, float y) {
45 int32_t ix0, iy0, ix, iy;
46
47 if (isnanf(x) || isnanf(y))
48 return 0;
49
50 ix = ix0 = *(int32_t *)&x;
51 iy = iy0 = *(int32_t *)&y;
52 if (ix < 0) {
53 ix = -ix;
54 if (!(iy0 < 0))
55 return 0;
56 }
57 if (iy < 0) {
58 iy = -iy;
59 if (!(ix0 < 0))
60 return 0;
61 }
62 return abs(ix - iy) <= kMaxUlps;
63 }
64
65 /* See AOSP bionic/tests/fenv_test.cpp */
66
TestRounding(float expectation1,float expectation2)67 static void TestRounding(float expectation1, float expectation2) {
68 // volatile to prevent compiler optimizations.
69 volatile float f = 1.968750f;
70 volatile float m = 0x1.0p23f;
71 volatile float x = f + m;
72 ASSERT_FLOAT_EQ(expectation1, x);
73 x -= m;
74 ASSERT_EQ(expectation2, x);
75 }
76
DivideByZero()77 static void DivideByZero() {
78 // volatile to prevent compiler optimizations.
79 volatile float zero = 0.0f;
80 volatile float result __attribute__((unused)) = 123.0f / zero;
81 }
82
TEST(fenv,fesetround_fegetround_FE_TONEAREST)83 TEST(fenv, fesetround_fegetround_FE_TONEAREST) {
84 fesetround(FE_TONEAREST);
85 ASSERT_EQ(FE_TONEAREST, fegetround());
86 TestRounding(8388610.0f, 2.0f);
87 }
88
TEST(fenv,fesetround_fegetround_FE_TOWARDZERO)89 TEST(fenv, fesetround_fegetround_FE_TOWARDZERO) {
90 fesetround(FE_TOWARDZERO);
91 ASSERT_EQ(FE_TOWARDZERO, fegetround());
92 TestRounding(8388609.0f, 1.0f);
93 }
94
TEST(fenv,fesetround_fegetround_FE_UPWARD)95 TEST(fenv, fesetround_fegetround_FE_UPWARD) {
96 fesetround(FE_UPWARD);
97 ASSERT_EQ(FE_UPWARD, fegetround());
98 TestRounding(8388610.0f, 2.0f);
99 }
100
TEST(fenv,fesetround_fegetround_FE_DOWNWARD)101 TEST(fenv, fesetround_fegetround_FE_DOWNWARD) {
102 fesetround(FE_DOWNWARD);
103 ASSERT_EQ(FE_DOWNWARD, fegetround());
104 TestRounding(8388609.0f, 1.0f);
105 }
106
TEST(fenv,feclearexcept_fetestexcept)107 TEST(fenv, feclearexcept_fetestexcept) {
108 // Clearing clears.
109 feclearexcept(FE_ALL_EXCEPT);
110 ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
111
112 // Dividing by zero sets FE_DIVBYZERO.
113 DivideByZero();
114 int raised = fetestexcept(FE_DIVBYZERO | FE_OVERFLOW);
115 ASSERT_TRUE((raised & FE_OVERFLOW) == 0);
116 ASSERT_TRUE((raised & FE_DIVBYZERO) != 0);
117
118 // Clearing an unset bit is a no-op.
119 feclearexcept(FE_OVERFLOW);
120 ASSERT_TRUE((raised & FE_OVERFLOW) == 0);
121 ASSERT_TRUE((raised & FE_DIVBYZERO) != 0);
122
123 // Clearing a set bit works.
124 feclearexcept(FE_DIVBYZERO);
125 ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
126 }
127
main()128 int main()
129 {
130 fesetround_fegetround_FE_TONEAREST();
131 fesetround_fegetround_FE_TOWARDZERO();
132 fesetround_fegetround_FE_UPWARD();
133 fesetround_fegetround_FE_DOWNWARD();
134 feclearexcept_fetestexcept();
135 printf("total_fail = %d\n", total_fail);
136 return total_fail == 0 ? 0 : 1;
137 }
138