diff --git a/lib/std/math/math_nolibc/atan.c3 b/lib/std/math/math_nolibc/atan.c3 index dc2c26c9b..a307b2495 100644 --- a/lib/std/math/math_nolibc/atan.c3 +++ b/lib/std/math/math_nolibc/atan.c3 @@ -217,30 +217,21 @@ fn float _atanf(float x) @weak @extern("atanf") @nostrip const PI_LO @private = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ -macro void extract_words(double d, uint* hi, uint* lo) @private -{ - ulong rep = bitcast(d, ulong); - *hi = (uint)(rep >> 32); - *lo = (uint)rep; -} - fn double _atan2(double y, double x) @weak @extern("atan2") @nostrip { if (math::is_nan(x) || math::is_nan(y)) return x + y; - uint lx @noinit; - uint ix @noinit; - extract_words(x, &ix, &lx); - uint ly @noinit; - uint iy @noinit; - extract_words(y, &iy, &ly); + uint lx = x.low_word(); + uint ix = x.high_word(); + uint ly = y.low_word(); + uint iy = y.high_word(); // x = 1.0 if ((ix - 0x3ff00000) | lx == 0) return _atan(y); // 2*sign(x) + sign(y) uint m = ((iy >> 31) & 1) | ((ix >> 30) & 2); - ix = ix & 0x7fffffff; - iy = iy & 0x7fffffff; + ix &= 0x7fffffff; + iy &= 0x7fffffff; // when y = 0 if (iy | ly == 0) @@ -313,8 +304,8 @@ const float PI_LO_F @private = -8.7422776573e-08; /* 0xb3bbbd2e */ fn float _atan2f(float y, float x) @weak @extern("atan2f") @nostrip { if (math::is_nan(x) || math::is_nan(y)) return x + y; - uint ix = bitcast(x, uint); - uint iy = bitcast(y, uint); + uint ix = x.word(); + uint iy = y.word(); /* x=1.0 */ if (ix == 0x3f800000) return _atanf(y); /* 2*sign(x)+sign(y) */ diff --git a/lib/std/math/math_nolibc/cos.c3 b/lib/std/math/math_nolibc/cos.c3 index 2b4cbac13..7dcb16e10 100644 --- a/lib/std/math/math_nolibc/cos.c3 +++ b/lib/std/math/math_nolibc/cos.c3 @@ -2,7 +2,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH)); fn float _cosf(float x) @extern("cosf") @weak @nostrip { - uint ix = bitcast(x, uint); + uint ix = x.word(); uint sign = ix >> 31; ix &= 0x7fffffff; @@ -54,8 +54,7 @@ fn float _cosf(float x) @extern("cosf") @weak @nostrip fn double _cos(double x) @extern("cos") @weak @nostrip { // High word of x. - uint ix = (uint)(bitcast(x, ulong) >> 32); - ix &= 0x7fffffff; + uint ix = x.high_word() & 0x7fffffff; switch { diff --git a/lib/std/math/math_nolibc/sin.c3 b/lib/std/math/math_nolibc/sin.c3 index c91a8bae5..d6cf7aece 100644 --- a/lib/std/math/math_nolibc/sin.c3 +++ b/lib/std/math/math_nolibc/sin.c3 @@ -18,7 +18,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH)); fn float _sinf(float x) @weak @extern("sinf") @nostrip { - uint ix = bitcast(x, uint); + uint ix = x.word(); int sign = ix >> 31; ix &= 0x7fffffff; switch @@ -87,8 +87,7 @@ fn float _sinf(float x) @weak @extern("sinf") @nostrip fn double sin(double x) @extern("sin") @weak @nostrip { // High word of x. - uint ix = (uint)(bitcast(x, ulong) >> 32); - ix &= 0x7fffffff; + uint ix = x.high_word() & 0x7fffffff; switch { // |x| ~< pi/4 diff --git a/lib/std/math/math_nolibc/sincos.c3 b/lib/std/math/math_nolibc/sincos.c3 index 70050ddfa..15b744ea9 100644 --- a/lib/std/math/math_nolibc/sincos.c3 +++ b/lib/std/math/math_nolibc/sincos.c3 @@ -18,8 +18,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH)); fn void sincosf(float x, float *sin, float *cos) @extern("__sincosf") @weak @nostrip { - - uint ix = bitcast(x, uint); + uint ix = x.word(); uint sign = ix >> 31; ix &= 0x7fffffff; @@ -108,8 +107,7 @@ fn void sincosf(float x, float *sin, float *cos) @extern("__sincosf") @weak @nos fn void sincos(double x, double *sin, double *cos) @extern("__sincos") @weak @nostrip { // High word of x. - uint ix = (uint)(bitcast(x, ulong) >> 32); - ix &= 0x7fffffff; + uint ix = x.high_word() & 0x7fffffff; // |x| ~< pi/4 switch diff --git a/test/unit/stdlib/math/math.c3 b/test/unit/stdlib/math/math.c3 index edf9a4851..45c9ab369 100644 --- a/test/unit/stdlib/math/math.c3 +++ b/test/unit/stdlib/math/math.c3 @@ -303,12 +303,12 @@ fn void test_cos() @test fn void test_exp() @test { - int [<5>] in = { 2, 1, 0, -1, -2 }; - double [<5>] out = { 7.38905609893065, math::E , 1., 0.36787944117144233, 0.1353352832366127 }; - float [<2>] in2 = { 1.f, 0.f }; - float [<2>] out2 = { math::E, 1.f }; - double [<2>] in3 = { 1., 0. }; - double [<2>] out3 = { math::E, 1. }; + int[<5>] in = { 2, 1, 0, -1, -2 }; + double[<5>] out = { 7.38905609893065, math::E , 1., 0.36787944117144233, 0.1353352832366127 }; + float[<6>] in2 = { 1.8f, 0.6f, 0.4f, -0.4f, -0.8f, -1.8f }; + float[<6>] out2 = {6.049647464412946f, 1.8221188003905089f, 1.4918246976412703f, 0.6703200460356393f, 0.44932896411722156f, 0.16529888822158656f }; + double[<6>] in3 = { 1.8, 0.6, 0.4, -0.4, -0.8, -1.8 }; + double[<6>] out3 = {6.049647464412946, 1.8221188003905089, 1.4918246976412703, 0.6703200460356393, 0.44932896411722156, 0.16529888822158656 }; assert(@typeis(math::exp(in[0]), double)); assert(@typeis(math::exp((float)in[0]), float)); assert(@typeis(math::exp((double)in[0]), double)); @@ -321,9 +321,9 @@ fn void test_exp() @test x = math::exp((double)in[i]); assert(math::is_approx_rel(x, out[i], 1e-12), "exp(%f)=%f is not equal to %f", in[i], x, out[i]); } - float [<2>] vecf = math::exp(in2); - double [<2>] vec = math::exp(in3); - for (int i = 0; i < 2; i++) + float[<6>] vecf = math::exp(in2); + double[<6>] vec = math::exp(in3); + for (int i = 0; i < 6; i++) { assert(math::is_approx_rel(vecf[i], out2[i], 1e-6), "exp(%f)=%f is not equal to %f", in2[i], vecf[i], out2[i]); assert(math::is_approx_rel(vec[i], out3[i], 1e-12), "exp(%f)=%f is not equal to %f", in3[i], vec[i], out3[i]); @@ -356,15 +356,87 @@ fn void test_floor() @test fn void test_log() @test { - double x = math::E; - assert(math::log(x, x) == 1.0); - float y = math::E; - assert(math::log(y, y) == 1.0f); - $assert @typeis(math::log(y, y), float); - double[<3>] xx = { 2, 4, 8 }; - assert(math::log(xx, 2) == double[<3>] { 1.0, 2.0, 3.0 }); - float[<3>] yy = { 10, 100, 1000 }; - assert(math::log(yy, 10) == float[<3>] { 1.0, 2.0, 3.0 }); + int[<8>] in = { 1, 10, 100, 1000, 1, 4, 8, 16 }; + double[<8>] out = { 0., 1., 2., 3., 0., 2. / 3., 1., 4. / 3. }; + float[<4>] bf = { 1.f / math::E, 1.f / (math::E * math::E), 1.f / (math::E * math::E), 1.f / math::E }; + float[<4>] in2 = { math::E * math::E, math::E, 1.f / math::E, 1.f / (math::E * math::E) }; + float[<4>] out2 = { -2.f, -0.5f, 0.5f, 2.f }; + double[<4>] bx = { 1. / math::E, 1. / (math::E * math::E), 1. / (math::E * math::E), 1. / math::E }; + double[<4>] in3 = { math::E * math::E, math::E, 1. / math::E, 1. / (math::E * math::E) }; + double[<4>] out3 = { -2., -0.5, 0.5, 2. }; + assert(@typeis(math::log(in[0], in[0]), double)); + assert(@typeis(math::log(in[0], (float)in[0]), float)); + assert(@typeis(math::log((float)in[0], in[0]), float)); + assert(@typeis(math::log(in[0], (double)in[0]), double)); + assert(@typeis(math::log((double)in[0], in[0]), double)); + assert(@typeis(math::log((float)in[0], (float)in[0]), float)); + assert(@typeis(math::log((float)in[0], (double)in[0]), double)); + assert(@typeis(math::log((double)in[0], (float)in[0]), double)); + assert(@typeis(math::log((double)in[0], (double)in[0]), double)); + for (int i = 0; i < 8; i++) + { + int base = (i < 4) ? 10 : 8; + + double x = math::log(in[i], base); + assert(math::is_approx_rel(x, out[i], 1e-12), "log(%d,%d)=%f is not equal to %f", in[i], base, x, out[i]); + + float f = math::log((float)in[i], base); + assert(math::is_approx_rel(f, (float)out[i], 1e-6), "log(%f,%d)=%f is not equal to %f", in[i], base, f, out[i]); + + x = math::log((double)in[i], base); + assert(math::is_approx_rel(x, out[i], 1e-12), "log(%f,%d)=%f is not equal to %f", in[i], base, x, out[i]); + } + float[<4>] vecf = math::log(in2, bf); + double[<4>] vec = math::log(in3, bx); + for (int i = 0; i < 4; i++) + { + assert(math::is_approx_rel(vecf[i], out2[i], 1e-6), "log(%f,%f)=%f is not equal to %f", in2[i], bf[i], vecf[i], out2[i]); + assert(math::is_approx_rel(vec[i], out3[i], 1e-12), "log(%f,%f)=%f is not equal to %f", in3[i], bx[i], vec[i], out3[i]); + } +} + +fn void test_pow() @test +{ + int[<10>] e = { 2, 1, 0, -1, -2, 2, 1, 0, -1, -2 }; + double[<10>] out = { 100., 10., 1., 0.1, 0.01, 4., 2., 1., 0.5, 0.25 }; + float[<2>] base2 = { -1.f / math::E, 1.f / math::E }; + float[<5>] out2 = { 1.f / (math::E * math::E), 1.f / math::E, 1.f, math::E, math::E * math::E }; + double[<2>] base3 = { -1. / math::E, 1. / math::E }; + double[<5>] out3 = { 1. / (math::E * math::E), 1. / math::E, 1., math::E, math::E * math::E }; + assert(@typeis(math::pow(e[1], e[1]), double)); + assert(@typeis(math::pow((float)e[1], e[1]), float)); + assert(@typeis(math::pow((double)e[1], e[1]), double)); + for (int i = 0; i < 10; i++) + { + for (int j = 0; j < 2; j++) + { + int base = (2 * j - 1) * ((i < 5) ? 10 : 2); + + double x = math::pow(base, e[i]); + double outx = (e[i] & 1) ? (double)(2 * j - 1) * out[i] : out[i]; + assert(math::is_approx_rel(x, outx, 1e-12), "pow(%d,%d)=%f is not equal to %f", base, e[i], x, outx); + + float f = math::pow((float)base, e[i]); + float outf = (e[i] & 1) ? (float)(2 * j - 1) * (float)out[i] : (float)out[i]; + assert(math::is_approx_rel(f, outf, 1e-6), "pow(%d,%f)=%f is not equal to %f", base, e[i], f, outf); + + x = math::pow((double)base, e[i]); + assert(math::is_approx_rel(x, outx, 1e-12), "pow(%d,%f)=%f is not equal to %f", base, e[i], x, outx); + } + } + for (int i = 0; i < 5; i++) + { + float[<2>] vecf = math::pow(base2, e[i]); + double[<2>] vec = math::pow(base3, e[i]); + for (int j = 0; j < 2; j++) + { + float outf = (e[i] & 1) ? (float)(2 * j - 1) * (float)out2[i] : (float)out2[i]; + assert(math::is_approx_rel(vecf[j], outf, 1e-6), "pow(%f,%f)=%f is not equal to %f", base2[i], e[i], vecf[j], outf); + double outx = (e[i] & 1) ? (double)(2 * j - 1) * out3[i] : out3[i]; + assert(math::is_approx_rel(vec[j], outx, 1e-12), "pow(%f,%f)=%f is not equal to %f", base3[i], e[i], vec[j], outx); + } + } + } fn void test_sign() @test