diff --git a/include/FastSIMD/ToolSet/Generic/Functions.h b/include/FastSIMD/ToolSet/Generic/Functions.h index 217aeb8..ed5ca34 100644 --- a/include/FastSIMD/ToolSet/Generic/Functions.h +++ b/include/FastSIMD/ToolSet/Generic/Functions.h @@ -634,7 +634,7 @@ namespace FS RegisterF xx = value * value; y *= xx; - y *= e * RegisterF( -2.12194440e-4f ); + y += e * RegisterF( -2.12194440e-4f ); y -= xx * RegisterF( 0.5f ); value += y; @@ -648,12 +648,13 @@ namespace FS } } + // value <= 0 returns 0, matching 0^pow for pow > 0 template FS_FORCEINLINE Register Pow( const Register& value, const Register& pow ) { if constexpr( IsNativeV> ) { - return Exp( pow * Log( value ) ); + return Masked( value > Register( 0 ), Exp( pow * Log( value ) ) ); } else { diff --git a/tests/test.inl b/tests/test.inl index a24187a..716f40f 100644 --- a/tests/test.inl +++ b/tests/test.inl @@ -454,6 +454,14 @@ class FastSIMD::DispatchClass, SIMD> : publ b = FS::Min( FS::Max( b, TestRegf32( -8.0f ) ), TestRegf32( 8.0f ) ); return FS::Pow( a, b ); } ).relaxedAccuracy = 16384; + RegisterTest( tests, "f32 pow zero base", []( TestRegf32 a, TestRegf32 b ) { + // Negative inputs become a zero base, ranges avoid Exp overflow + auto zero = a < TestRegf32( 0.0f ); + a = FS::Min( FS::Max( a, TestRegf32( 1.e-4f ) ), TestRegf32( 1.e+4f ) ); + a = FS::Select( zero, TestRegf32( 0.0f ), a ); + b = FS::Min( FS::Max( FS::Abs( b ), TestRegf32( 0.1f ) ), TestRegf32( 8.0f ) ); + return FS::Pow( a, b ); + } ).relaxedAccuracy = 16384; RegisterTest( tests, "i32 convert to f32", []( TestRegi32 a ) { return FS::Convert( a ); } ); RegisterTest( tests, "f32 convert to i32", []( TestRegf32 a ) { return FS::Convert( FS::Min( FS::Max( a, TestRegf32( -2147483647 - 1 ) ), TestRegf32( 2147483520 ) ) ); } );