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; 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 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 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 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 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 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 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 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 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 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