diff --git a/include/EAStdC/EAFixedPoint.h b/include/EAStdC/EAFixedPoint.h index 5bb2a0e..2c31b17 100644 --- a/include/EAStdC/EAFixedPoint.h +++ b/include/EAStdC/EAFixedPoint.h @@ -134,12 +134,12 @@ namespace StdC /////////////////////////////////////////////////////////////////////////////// // class FPTemplate // -#define FPTemplateDeclaration template +#define FPTemplateDeclaration template #define FPTemplateType FPTemplate template + T upShiftInt, T downShiftInt, + T upMulInt, T downDivInt> struct FPTemplate { @@ -152,12 +152,12 @@ struct FPTemplate //Functions FPTemplate() {} FPTemplate(const FPTemplate& newValue) { value = newValue.value; } - FPTemplate(const int& newValue) { value = newValue << upShiftInt; } - FPTemplate(const unsigned int& newValue) { value = newValue << upShiftInt; } - FPTemplate(const long& newValue) { value = newValue << upShiftInt; } - FPTemplate(const unsigned long& newValue) { value = newValue << upShiftInt; } - FPTemplate(const float& newValue) { value = (int)(newValue * (float)upMulInt); } - FPTemplate(const double& newValue) { value = (int)(newValue * (double)upMulInt); } + FPTemplate(const int& newValue) { value = (T)(newValue) << upShiftInt; } + FPTemplate(const unsigned int& newValue) { value = (T)(newValue) << upShiftInt; } + FPTemplate(const long& newValue) { value = (T)(newValue) << upShiftInt; } + FPTemplate(const unsigned long& newValue) { value = (T)(newValue) << upShiftInt; } + FPTemplate(const float& newValue) { value = (T)(newValue * (float)upMulInt); } + FPTemplate(const double& newValue) { value = (T)(newValue * (double)upMulInt); } void FromFixed(const int& newValue) { value = newValue; } // Accepts an int that is in fixed point format (i.e. shifted) already. T AsFixed () { return value; } // Allows you to get the fixed point value itself and mess with it as you want. @@ -245,15 +245,15 @@ struct FPTemplate FPTemplate& operator+=(const unsigned int& argValue) { value += (T)(argValue<>=(int numBits) { value >>= numBits; return *this;} - FPTemplate& operator++() { value += 1< UFixed10; typedef FPTemplate SFixed8; // 8:24 fixed point (24 bits of fraction) typedef FPTemplate UFixed8; +typedef FPTemplate SFixed32; // 32:32 fixed point (32 bits of fraction) + /////////////////////////////////////////////////////////////////////////////// #define FPDeclareTemplateSpecializations(TypeDef) \ diff --git a/test/source/TestFixedPoint.cpp b/test/source/TestFixedPoint.cpp index 5aa90fa..b213920 100644 --- a/test/source/TestFixedPoint.cpp +++ b/test/source/TestFixedPoint.cpp @@ -8,6 +8,7 @@ #include #include #include +#include @@ -57,8 +58,43 @@ static bool CompareValues(EA::StdC::SFixed16 a, double b) const volatile uint64_t c = ((uint64_t)a) << 8; return (int32_t)(uint32_t)(c % b); } + + static bool CompareValues(SFixed32 a, double b) { + #define Fixed32ToDouble(a) (((double)a) / (65536.0 * 65536.0)) + + const double c = Fixed32ToDouble(a.AsFixed()); + return (fabs(c - b) < 0.01); + } + template <> + EASTDC_API int64_t FP_PASCAL SFixed32::FixedMul(const int64_t lhs, + const int64_t rhs) { + int128_t lhs128(lhs); + lhs128 *= rhs; + lhs128 >>= 32; + + return lhs128.AsInt64(); + } + + template <> + EASTDC_API int64_t FP_PASCAL SFixed32::FixedDiv(const int64_t lhs, + const int64_t rhs) { + int128_t lhs128(lhs); + lhs128 <<= 32; + lhs128 /= rhs; + + return lhs128.AsInt64(); + } + + template <> + EASTDC_API int64_t FP_PASCAL SFixed32::FixedMod(const int64_t lhs, + const int64_t rhs) { + int128_t c(lhs); + c <<= 32; + return (c % rhs).AsInt64(); + } } } + #endif @@ -224,6 +260,84 @@ int TestFixedPoint() if(!CompareValues(a, 0.77333)) nErrorCount++; } + + //Test SFixed32 + { + SFixed32 a(1), b(2), c(3.f), d(1.0); + double e = 3.2; + float f = 4.5; + int g = 6; + + if (a.AsInt() != 1) nErrorCount++; + if (c.AsUnsignedInt() != 3) nErrorCount++; + if (a.AsLong() != 1) nErrorCount++; + if (c.AsUnsignedLong() != 3) nErrorCount++; + if (!CompareValues((double)a.AsFloat(), 1.0)) nErrorCount++; + if (!CompareValues(c.AsDouble(), 3.0)) nErrorCount++; + + a = b * f; + if (!CompareValues(a, 9.0)) nErrorCount++; + + a = b / d; + if (!CompareValues(a, 2.0)) nErrorCount++; + + a = b + d; + if (!CompareValues(a, 3.0)) nErrorCount++; + + a = (c / e) + b + f; + if (!CompareValues(a, 7.4375)) nErrorCount++; + + a = c / e * (b % g) + f / c; + if (!CompareValues(a, 3.375)) nErrorCount++; + + if (!CompareValues(b, 2.0)) nErrorCount++; + a = g * -c / (b++); + if (!CompareValues(a, -9.0)) nErrorCount++; + if (!CompareValues(b, 3.0)) nErrorCount++; + --b; // Restore it to its original value. + if (!CompareValues(b, 2.0)) nErrorCount++; + + a = sin(d) + pow(b, e) * sqrt(d); + if (!CompareValues(a, 10.031)) nErrorCount++; + + a = log(e) / log(f); + if (!CompareValues(a, 0.77333)) + nErrorCount++; + } + + { + SFixed32 a(16); + + auto expected = a.value << 1; + + a = (a << 1); + + if (!CompareValues(a.value, expected)) nErrorCount++; + } + + // FPTemplate operator>>(int numBits) const + { + SFixed32 a(16); + + auto expected = a.value >> 1; + + a = (a >> 1); + + if (!CompareValues(a.value, expected)) nErrorCount++; + } + + // Reported regression - ensure operator<< and operator>> are + // implemented correctly. + { + SFixed32 a(16); + + auto expected = a.value; + + a = (a << 1); + a = (a >> 1); + + if (!CompareValues(a.value, expected)) nErrorCount++; + } #endif // Test core multiplication/division functions