Explorar el Código

Added rcpSafe.

Бранимир Караџић hace 1 año
padre
commit
b8741eaf6f
Se han modificado 3 ficheros con 113 adiciones y 51 borrados
  1. 34 9
      include/bx/inline/math.inl
  2. 14 0
      include/bx/math.h
  3. 65 42
      tests/math_test.cpp

+ 34 - 9
include/bx/inline/math.inl

@@ -411,7 +411,7 @@ namespace bx
 
 	inline BX_CONST_FUNC float rsqrtRef(float _a)
 	{
-		if (_a < kNearZero)
+		if (_a < kFloatSmallest)
 		{
 			return kFloatInfinity;
 		}
@@ -421,7 +421,7 @@ namespace bx
 
 	inline BX_CONST_FUNC float rsqrtSimd(float _a)
 	{
-		if (_a < kNearZero)
+		if (_a < kFloatSmallest)
 		{
 			return kFloatInfinity;
 		}
@@ -441,7 +441,7 @@ namespace bx
 
 	inline BX_CONST_FUNC float sqrtRef(float _a)
 	{
-		if (_a < 0.0F)
+		if (_a < 0.0f)
 		{
 			return bitsToFloat(kFloatExponentMask | kFloatMantissaMask);
 		}
@@ -451,11 +451,11 @@ namespace bx
 
 	inline BX_CONST_FUNC float sqrtSimd(float _a)
 	{
-		if (_a < 0.0F)
+		if (_a < 0.0f)
 		{
 			return bitsToFloat(kFloatExponentMask | kFloatMantissaMask);
 		}
-		else if (_a < kNearZero)
+		else if (_a < kFloatSmallest)
 		{
 			return 0.0f;
 		}
@@ -527,9 +527,14 @@ namespace bx
 		return 1.0f / _a;
 	}
 
+	inline BX_CONSTEXPR_FUNC float rcpSafe(float _a)
+	{
+		return rcp(copySign(max(kFloatSmallest, abs(_a) ), _a) );
+	}
+
 	inline BX_CONSTEXPR_FUNC float mod(float _a, float _b)
 	{
-		return _a - _b * floor(_a / _b);
+		return _a - _b * floor(mul(_a, rcp(_b) ) );
 	}
 
 	inline BX_CONSTEXPR_FUNC bool isEqual(float _a, float _b, float _epsilon)
@@ -803,11 +808,21 @@ namespace bx
 		return mul(_a, rcp(_b) );
 	}
 
+	inline BX_CONSTEXPR_FUNC Vec3 divSafe(const Vec3 _a, const Vec3 _b)
+	{
+		return mul(_a, rcpSafe(_b) );
+	}
+
 	inline BX_CONSTEXPR_FUNC Vec3 div(const Vec3 _a, float _b)
 	{
 		return mul(_a, rcp(_b) );
 	}
 
+	inline BX_CONSTEXPR_FUNC Vec3 divSafe(const Vec3 _a, float _b)
+	{
+		return mul(_a, rcpSafe(_b) );
+	}
+
 	inline BX_CONSTEXPR_FUNC Vec3 nms(const Vec3 _a, const float _b, const Vec3 _c)
 	{
 		return sub(_c, mul(_a, _b) );
@@ -910,9 +925,19 @@ namespace bx
 	{
 		return
 		{
-			1.0f / _a.x,
-			1.0f / _a.y,
-			1.0f / _a.z,
+			rcp(_a.x),
+			rcp(_a.y),
+			rcp(_a.z),
+		};
+	}
+
+	inline BX_CONSTEXPR_FUNC Vec3 rcpSafe(const Vec3 _a)
+	{
+		return
+		{
+			rcpSafe(_a.x),
+			rcpSafe(_a.y),
+			rcpSafe(_a.z),
 		};
 	}
 

+ 14 - 0
include/bx/math.h

@@ -355,6 +355,10 @@ namespace bx
 	///
 	BX_CONSTEXPR_FUNC float rcp(float _a);
 
+	/// Returns reciprocal of _a.
+	///
+	BX_CONSTEXPR_FUNC float rcpSafe(float _a);
+
 	/// Returns the floating-point remainder of the division operation _a/_b.
 	///
 	BX_CONSTEXPR_FUNC float mod(float _a, float _b);
@@ -431,9 +435,15 @@ namespace bx
 	///
 	BX_CONSTEXPR_FUNC Vec3 div(const Vec3 _a, const Vec3 _b);
 
+	///
+	BX_CONSTEXPR_FUNC Vec3 divSafe(const Vec3 _a, const Vec3 _b);
+
 	///
 	BX_CONSTEXPR_FUNC Vec3 div(const Vec3 _a, float _b);
 
+	///
+	BX_CONSTEXPR_FUNC Vec3 divSafe(const Vec3 _a, float _b);
+
 	/// Returns result of negated multiply-sub operation -(_a * _b - _c) -> _c - _a * _b.
 	///
 	BX_CONSTEXPR_FUNC Vec3 nms(const Vec3 _a, const float _b, const Vec3 _c);
@@ -482,6 +492,10 @@ namespace bx
 	///
 	BX_CONSTEXPR_FUNC Vec3 rcp(const Vec3 _a);
 
+	/// Returns component wise reciprocal of _a.
+	///
+	BX_CONSTEXPR_FUNC Vec3 rcpSafe(const Vec3 _a);
+
 	///
 	BX_CONSTEXPR_FUNC bool isEqual(const Vec3 _a, const Vec3 _b, float _epsilon);
 

+ 65 - 42
tests/math_test.cpp

@@ -22,9 +22,9 @@ TEST_CASE("isFinite, isInfinite, isNan", "[math]")
 		REQUIRE(::__isfinitef(u.f) == bx::isFinite(u.f) );
 		REQUIRE(::__isinff(u.f)    == bx::isInfinite(u.f) );
 #elif BX_COMPILER_MSVC
-		REQUIRE(!!::isnan(u.f)    == bx::isNan(u.f));
-		REQUIRE(!!::isfinite(u.f) == bx::isFinite(u.f));
-		REQUIRE(!!::isinf(u.f)    == bx::isInfinite(u.f));
+		REQUIRE(!!::isnan(u.f)    == bx::isNan(u.f) );
+		REQUIRE(!!::isfinite(u.f) == bx::isFinite(u.f) );
+		REQUIRE(!!::isinf(u.f)    == bx::isInfinite(u.f) );
 #else
 		REQUIRE(::isnanf(u.f)  == bx::isNan(u.f) );
 		REQUIRE(::finitef(u.f) == bx::isFinite(u.f) );
@@ -148,7 +148,7 @@ TEST_CASE("floorLog2", "[math]")
 	}
 }
 
-TEST_CASE("ceil/floorLog2", "[math]")
+TEST_CASE("ceilLog2 & floorLog2", "[math]")
 {
 	{
 		uint32_t prev = 0;
@@ -234,40 +234,56 @@ TEST_CASE("findFirstSet", "[math]")
 BX_PRAGMA_DIAGNOSTIC_PUSH();
 BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4723) // potential divide by 0
 
+TEST_CASE("rcp", "[math][libm]")
+{
+	REQUIRE(1.0f == bx::rcp(1.0f) );
+	REQUIRE(2.0f == bx::rcp(0.5f) );
+	REQUIRE(bx::isInfinite(bx::rcp( 0.0f) ) );
+	REQUIRE(bx::isInfinite(bx::rcp(-0.0f) ) );
+}
+
+TEST_CASE("rcpSafe", "[math][libm]")
+{
+	REQUIRE(1.0f == bx::rcpSafe(1.0f) );
+	REQUIRE(2.0f == bx::rcpSafe(0.5f) );
+	REQUIRE(!bx::isInfinite(bx::rcpSafe( 0.0f) ) );
+	REQUIRE(!bx::isInfinite(bx::rcpSafe(-0.0f) ) );
+}
+
 TEST_CASE("rsqrt", "[math][libm]")
 {
 	bx::WriterI* writer = bx::getNullOut();
 	bx::Error err;
 
 	// rsqrtRef
-	REQUIRE(bx::isInfinite(bx::rsqrtRef(0.0f)));
+	REQUIRE(bx::isInfinite(bx::rsqrtRef(0.0f) ) );
 
 	for (float xx = bx::kNearZero; xx < 100.0f; xx += 0.1f)
 	{
-		bx::write(writer, &err, "rsqrtRef(%f) == %f (expected: %f)\n", xx, bx::rsqrtRef(xx), 1.0f / ::sqrtf(xx));
-		REQUIRE(err.isOk());
-		REQUIRE(bx::isEqual(bx::rsqrtRef(xx), 1.0f / ::sqrtf(xx), 0.00001f));
+		bx::write(writer, &err, "rsqrtRef(%f) == %f (expected: %f)\n", xx, bx::rsqrtRef(xx), 1.0f / ::sqrtf(xx) );
+		REQUIRE(err.isOk() );
+		REQUIRE(bx::isEqual(bx::rsqrtRef(xx), 1.0f / ::sqrtf(xx), 0.00001f) );
 	}
 
 	// rsqrtSimd
-	REQUIRE(bx::isInfinite(bx::rsqrtSimd(0.0f)));
+	REQUIRE(bx::isInfinite(bx::rsqrtSimd(0.0f) ) );
 
 	for (float xx = bx::kNearZero; xx < 100.0f; xx += 0.1f)
 	{
-		bx::write(writer, &err, "rsqrtSimd(%f) == %f (expected: %f)\n", xx, bx::rsqrtSimd(xx), 1.0f / ::sqrtf(xx));
-		REQUIRE(err.isOk());
-		REQUIRE(bx::isEqual(bx::rsqrtSimd(xx), 1.0f / ::sqrtf(xx), 0.00001f));
+		bx::write(writer, &err, "rsqrtSimd(%f) == %f (expected: %f)\n", xx, bx::rsqrtSimd(xx), 1.0f / ::sqrtf(xx) );
+		REQUIRE(err.isOk() );
+		REQUIRE(bx::isEqual(bx::rsqrtSimd(xx), 1.0f / ::sqrtf(xx), 0.00001f) );
 	}
 
 	// rsqrt
-	REQUIRE(bx::isInfinite(1.0f / ::sqrtf(0.0f)));
-	REQUIRE(bx::isInfinite(bx::rsqrt(0.0f)));
+	REQUIRE(bx::isInfinite(1.0f / ::sqrtf(0.0f) ) );
+	REQUIRE(bx::isInfinite(bx::rsqrt(0.0f) ) );
 
 	for (float xx = bx::kNearZero; xx < 100.0f; xx += 0.1f)
 	{
-		bx::write(writer, &err, "rsqrt(%f) == %f (expected: %f)\n", xx, bx::rsqrt(xx), 1.0f / ::sqrtf(xx));
-		REQUIRE(err.isOk());
-		REQUIRE(bx::isEqual(bx::rsqrt(xx), 1.0f / ::sqrtf(xx), 0.00001f));
+		bx::write(writer, &err, "rsqrt(%f) == %f (expected: %f)\n", xx, bx::rsqrt(xx), 1.0f / ::sqrtf(xx) );
+		REQUIRE(err.isOk() );
+		REQUIRE(bx::isEqual(bx::rsqrt(xx), 1.0f / ::sqrtf(xx), 0.00001f) );
 	}
 }
 
@@ -277,54 +293,54 @@ TEST_CASE("sqrt", "[math][libm]")
 	bx::Error err;
 
 	// sqrtRef
-	REQUIRE(bx::isNan(bx::sqrtRef(-1.0f)));
-	REQUIRE(bx::isEqual(bx::sqrtRef(0.0f), ::sqrtf(0.0f), 0.0f));
-	REQUIRE(bx::isEqual(bx::sqrtRef(1.0f), ::sqrtf(1.0f), 0.0f));
+	REQUIRE(bx::isNan(bx::sqrtRef(-1.0f) ) );
+	REQUIRE(bx::isEqual(bx::sqrtRef(0.0f), ::sqrtf(0.0f), 0.0f) );
+	REQUIRE(bx::isEqual(bx::sqrtRef(1.0f), ::sqrtf(1.0f), 0.0f) );
 
 	for (float xx = 0.0f; xx < 1000000.0f; xx += 1000.f)
 	{
-		bx::write(writer, &err, "sqrtRef(%f) == %f (expected: %f)\n", xx, bx::sqrtRef(xx), ::sqrtf(xx));
-		REQUIRE(err.isOk());
-		REQUIRE(bx::isEqual(bx::sqrtRef(xx), ::sqrtf(xx), 0.00001f));
+		bx::write(writer, &err, "sqrtRef(%f) == %f (expected: %f)\n", xx, bx::sqrtRef(xx), ::sqrtf(xx) );
+		REQUIRE(err.isOk() );
+		REQUIRE(bx::isEqual(bx::sqrtRef(xx), ::sqrtf(xx), 0.00001f) );
 	}
 
 	// sqrtSimd
-	REQUIRE(bx::isNan(bx::sqrtSimd(-1.0f)));
-	REQUIRE(bx::isEqual(bx::sqrtSimd(0.0f), ::sqrtf(0.0f), 0.0f));
-	REQUIRE(bx::isEqual(bx::sqrtSimd(1.0f), ::sqrtf(1.0f), 0.0f));
+	REQUIRE(bx::isNan(bx::sqrtSimd(-1.0f) ) );
+	REQUIRE(bx::isEqual(bx::sqrtSimd(0.0f), ::sqrtf(0.0f), 0.0f) );
+	REQUIRE(bx::isEqual(bx::sqrtSimd(1.0f), ::sqrtf(1.0f), 0.0f) );
 
 	for (float xx = 0.0f; xx < 1000000.0f; xx += 1000.f)
 	{
-		bx::write(writer, &err, "sqrtSimd(%f) == %f (expected: %f)\n", xx, bx::sqrtSimd(xx), ::sqrtf(xx));
-		REQUIRE(err.isOk());
-		REQUIRE(bx::isEqual(bx::sqrtSimd(xx), ::sqrtf(xx), 0.00001f));
+		bx::write(writer, &err, "sqrtSimd(%f) == %f (expected: %f)\n", xx, bx::sqrtSimd(xx), ::sqrtf(xx) );
+		REQUIRE(err.isOk() );
+		REQUIRE(bx::isEqual(bx::sqrtSimd(xx), ::sqrtf(xx), 0.00001f) );
 	}
 
 	for (float xx = 0.0f; xx < 100.0f; xx += 0.1f)
 	{
-		bx::write(writer, &err, "sqrt(%f) == %f (expected: %f)\n", xx, bx::sqrt(xx), ::sqrtf(xx));
-		REQUIRE(err.isOk());
-		REQUIRE(bx::isEqual(bx::sqrt(xx), ::sqrtf(xx), 0.00001f));
+		bx::write(writer, &err, "sqrt(%f) == %f (expected: %f)\n", xx, bx::sqrt(xx), ::sqrtf(xx) );
+		REQUIRE(err.isOk() );
+		REQUIRE(bx::isEqual(bx::sqrt(xx), ::sqrtf(xx), 0.00001f) );
 	}
 
 	// sqrt
-	REQUIRE(bx::isNan(::sqrtf(-1.0f)));
-	REQUIRE(bx::isNan(bx::sqrt(-1.0f)));
-	REQUIRE(bx::isEqual(bx::sqrt(0.0f), ::sqrtf(0.0f), 0.0f));
-	REQUIRE(bx::isEqual(bx::sqrt(1.0f), ::sqrtf(1.0f), 0.0f));
+	REQUIRE(bx::isNan(::sqrtf(-1.0f) ) );
+	REQUIRE(bx::isNan(bx::sqrt(-1.0f) ) );
+	REQUIRE(bx::isEqual(bx::sqrt(0.0f), ::sqrtf(0.0f), 0.0f) );
+	REQUIRE(bx::isEqual(bx::sqrt(1.0f), ::sqrtf(1.0f), 0.0f) );
 
 	for (float xx = 0.0f; xx < 1000000.0f; xx += 1000.f)
 	{
-		bx::write(writer, &err, "sqrt(%f) == %f (expected: %f)\n", xx, bx::sqrt(xx), ::sqrtf(xx));
-		REQUIRE(err.isOk());
-		REQUIRE(bx::isEqual(bx::sqrt(xx), ::sqrtf(xx), 0.00001f));
+		bx::write(writer, &err, "sqrt(%f) == %f (expected: %f)\n", xx, bx::sqrt(xx), ::sqrtf(xx) );
+		REQUIRE(err.isOk() );
+		REQUIRE(bx::isEqual(bx::sqrt(xx), ::sqrtf(xx), 0.00001f) );
 	}
 
 	for (float xx = 0.0f; xx < 100.0f; xx += 0.1f)
 	{
-		bx::write(writer, &err, "sqrt(%f) == %f (expected: %f)\n", xx, bx::sqrt(xx), ::sqrtf(xx));
-		REQUIRE(err.isOk());
-		REQUIRE(bx::isEqual(bx::sqrt(xx), ::sqrtf(xx), 0.00001f));
+		bx::write(writer, &err, "sqrt(%f) == %f (expected: %f)\n", xx, bx::sqrt(xx), ::sqrtf(xx) );
+		REQUIRE(err.isOk() );
+		REQUIRE(bx::isEqual(bx::sqrt(xx), ::sqrtf(xx), 0.00001f) );
 	}
 }
 
@@ -341,6 +357,10 @@ TEST_CASE("abs", "[math][libm]")
 TEST_CASE("mod", "[math][libm]")
 {
 	REQUIRE(389.0f == bx::mod(1389.0f, 1000.0f) );
+	REQUIRE( 89.0f == bx::mod(1389.0f, 100.0f) );
+	REQUIRE(  9.0f == bx::mod(1389.0f, 10.0f) );
+	REQUIRE(  4.0f == bx::mod(1389.0f, 5.0f) );
+	REQUIRE(  1.0f == bx::mod(1389.0f, 2.0f) );
 }
 
 TEST_CASE("floor", "[math][libm]")
@@ -760,4 +780,7 @@ TEST_CASE("limits", "[math]")
 
 	STATIC_REQUIRE(bx::LimitsT<double>::min == std::numeric_limits<double>::lowest() );
 	STATIC_REQUIRE(bx::LimitsT<double>::max == std::numeric_limits<double>::max() );
+
+	STATIC_REQUIRE(bx::kFloatSmallest  == std::numeric_limits<float>::min() );
+	STATIC_REQUIRE(bx::kDoubleSmallest == std::numeric_limits<double>::min() );
 }