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