/* * Copyright (c) 2023 Lawrence King * * SPDX-License-Identifier: Apache-2.0 * */ #include #include #include #define local_abs(x) (((x) < 0) ? -(x) : (x)) #ifndef NAN #define NAN (__builtin_nansf("")) #endif #ifndef INFINITY #define INFINITY (__builtin_inff()) #endif static float test_floats[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, /* numbers across the decade */ 3.14159265359f, 2.718281828f, /* irrational numbers pi and e */ 123.4f, 0.025f, 0.10f, 1.875f /* numbers with infinite */ /* repeating binary representation */ }; #define NUM_TEST_FLOATS (sizeof(test_floats)/sizeof(float)) static double test_doubles[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, /* numbers across the decade */ 3.14159265359, 2.718281828, /* irrational numbers pi and e */ 123.4, 0.025, 0.10, 1.875 /* numbers with infinite */ /* repeating binary representationa */ }; #define NUM_TEST_DOUBLES (sizeof(test_floats)/sizeof(float)) #ifndef isinf static int isinf(double x) { union { uint64_t u; double d; } ieee754; ieee754.d = x; ieee754.u &= ~0x8000000000000000; /* ignore the sign */ return ((ieee754.u >> 52) == 0x7FF) && ((ieee754.u & 0x000fffffffffffff) == 0); } #endif #ifndef isnan static int isnan(double x) { union { uint64_t u; double d; } ieee754; ieee754.d = x; ieee754.u &= ~0x8000000000000000; /* ignore the sign */ return ((ieee754.u >> 52) == 0x7FF) && ((ieee754.u & 0x000fffffffffffff) != 0); } #endif #ifndef isinff static int isinff(float x) { union { uint32_t u; float f; } ieee754; ieee754.f = x; ieee754.u &= ~0x80000000; /* ignore the sign */ return ((ieee754.u >> 23) == 0xFF) && ((ieee754.u & 0x7FFFFF) == 0); } #endif #ifndef isnanf static int isnanf(float x) { union { uint32_t u; float f; } ieee754; ieee754.f = x; ieee754.u &= ~0x80000000; /* ignore the sign */ return ((ieee754.u >> 23) == 0xFF) && ((ieee754.u & 0x7FFFFF) != 0); } #endif /* small errors are expected, computed as percentage error */ #define MAX_FLOAT_ERROR_PERCENT (3.5e-5f) #define MAX_DOUBLE_ERROR_PERCENT (4.5e-14) ZTEST(libc_common, test_sqrtf) { int i; float exponent, resf, square, root_squared, error; uint32_t max_error; int32_t ierror; int32_t *p_square = (int32_t *)□ int32_t *p_root_squared = (int32_t *)&root_squared; max_error = 0; /* test the special cases of 0.0, NAN, -NAN, INFINITY, -INFINITY, and -10.0 */ zassert_true(sqrtf(0.0f) == 0.0f, "sqrtf(0.0)"); zassert_true(isnanf(sqrtf(NAN)), "sqrt(nan)"); #ifdef issignallingf zassert_true(issignallingf(sqrtf(NAN)), "ssignalingf(sqrtf(nan))"); /* printf("issignallingf();\n"); */ #endif zassert_true(isnanf(sqrtf(-NAN)), "isnanf(sqrtf(-nan))"); zassert_true(isinff(sqrtf(INFINITY)), "isinff(sqrt(inf))"); zassert_true(isnanf(sqrtf(-INFINITY)), "isnanf(sqrt(-inf))"); zassert_true(isnanf(sqrtf(-10.0f)), "isnanf(sqrt(-10.0))"); for (exponent = 1.0e-10f; exponent < 1.0e10f; exponent *= 10.0f) { for (i = 0; i < NUM_TEST_FLOATS; i++) { square = test_floats[i] * exponent; resf = sqrtf(square); root_squared = resf * resf; zassert_true((resf > 0.0f) && (resf < INFINITY), "sqrtf out of range"); if ((resf > 0.0f) && (resf < INFINITY)) { error = (square - root_squared) / square * 100; if (error < 0.0f) { error = -error; } /* square and root_squared should be almost identical * except the last few bits, the EXOR will only set * the bits that are different */ ierror = (*p_square - *p_root_squared); ierror = local_abs(ierror); if (ierror > max_error) { max_error = ierror; } } else { /* negative, +NaN, -NaN, inf or -inf */ error = 0.0f; } zassert_true(error < MAX_FLOAT_ERROR_PERCENT, "max sqrtf error exceeded"); } } zassert_true(max_error < 0x03, "huge errors in sqrt implementation"); /* print the max error */ TC_PRINT("test_sqrtf max error %d counts\n", max_error); } ZTEST(libc_common, test_sqrt) { int i; double resd, error, square, root_squared, exponent; uint64_t max_error; int64_t ierror; int64_t *p_square = (int64_t *)□ int64_t *p_root_squared = (int64_t *)&root_squared; max_error = 0; /* test the special cases of 0.0, NAN, -NAN, INFINITY, -INFINITY, and -10.0 */ zassert_true(sqrt(0.0) == 0.0, "sqrt(0.0)"); zassert_true(isnan(sqrt((double)NAN)), "sqrt(nan)"); #ifdef issignalling zassert_true(issignalling(sqrt((double)NAN)), "ssignaling(sqrt(nan))"); /* printf("issignalling();\n"); */ #endif zassert_true(isnan(sqrt((double)-NAN)), "isnan(sqrt(-nan))"); zassert_true(isinf(sqrt((double)INFINITY)), "isinf(sqrt(inf))"); zassert_true(isnan(sqrt((double)-INFINITY)), "isnan(sqrt(-inf))"); zassert_true(isnan(sqrt(-10.0)), "isnan(sqrt(-10.0))"); for (exponent = 1.0e-10; exponent < 1.0e10; exponent *= 10.0) { for (i = 0; i < NUM_TEST_DOUBLES; i++) { square = test_doubles[i] * exponent; resd = sqrt(square); root_squared = resd * resd; zassert_true((resd > 0.0) && (resd < (double)INFINITY), "sqrt out of range"); if ((resd > 0.0) && (resd < (double)INFINITY)) { error = (square - root_squared) / square * 100; if (error < 0.0) { error = -error; } /* square and root_squared should be almost identical * except the last few bits, the EXOR will only set * the bits that are different */ ierror = (*p_square - *p_root_squared); ierror = local_abs(ierror); if (ierror > max_error) { max_error = ierror; } } else { /* negative, +NaN, -NaN, inf or -inf */ error = 0.0; } zassert_true(error < MAX_DOUBLE_ERROR_PERCENT, "max sqrt error exceeded"); } } zassert_true(max_error < 0x04, "huge errors in sqrt implementation"); /* print the max error */ TC_PRINT("test_sqrt max error %d counts\n", (uint32_t)max_error); }