Skip to content

Commit

Permalink
bug fix div operator for fast posit<16,2>
Browse files Browse the repository at this point in the history
  • Loading branch information
Ravenwater committed Jan 3, 2024
1 parent 4df2dac commit baf347a
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 71 deletions.
56 changes: 26 additions & 30 deletions include/universal/number/posit/specialized/posit_16_2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ class posit<NBITS_IS_16, ES_IS_2> {
if (!rcarry) {
if (exp == 0) {
--m;
exp = 3;
exp = 0x3u;
}
else {
--exp;
Expand Down Expand Up @@ -844,7 +844,7 @@ class posit<NBITS_IS_16, ES_IS_2> {
}
return bits;
}
uint16_t divRound(const int8_t m, uint16_t exp, uint32_t fraction, bool nonZeroRemainder) const noexcept {
uint16_t divRound(const int8_t m, uint16_t exp, uint32_t frac32, bool nonZeroRemainder) const noexcept {
uint16_t reglen, regime, bits;
if (m < 0) {
reglen = (-m & 0xFFFF);
Expand All @@ -859,38 +859,34 @@ class posit<NBITS_IS_16, ES_IS_2> {
bits = (m<0 ? 0x0001 : 0x7FFF); // minpos and maxpos
}
else {
fraction &= 0x3FFF; // remove both carry bits
uint16_t final_fbits = uint16_t(fraction >> (reglen + 2));
frac32 &= 0x3FFF; // remove both carry bits
uint16_t fraction = uint16_t(frac32 >> (reglen + 2));

bool bitNPlusOne = false;
if (reglen != 14) {
bitNPlusOne = bool((fraction >> (reglen + 1)) & 0x1);
}
else if (final_fbits > 0) {
final_fbits = 0;
}
if (reglen == 14 && exp != 0) {
bitNPlusOne = true;
exp = 0;
}
else {
uint16_t moreBits{ 0 };
if (reglen <= 12) {
bitNPlusOne = bool((frac32 >> (reglen + 1)) & 0x1);
exp <<= (12 - reglen);
if (bitNPlusOne) moreBits = (((1ull << (reglen + 1)) - 1ull) & frac32) ? 0x1 : 0x0;
}
//std::cout << "regime : " << to_binary(regime, 16, true) << '\n';
//std::cout << "exponent : " << to_binary(exp, 16, true) << '\n';
//std::cout << "fraction : " << to_binary(final_fbits, 16, true) << '\n';
bits = uint16_t(regime) | uint16_t(exp) | uint16_t(final_fbits);
//std::cout << "bits : " << to_binary(bits, 16, true) << '\n';

if (bitNPlusOne) {
//uint16_t more = (fraction & ((1 << reglen) - 1));
//std::cout << "morebits : " << to_binary(more, 16, true) << '\n';
//uint16_t mask = ((1 << reglen) - 1);
//std::cout << "mask : " << to_binary(mask, 16, true) << '\n';
uint16_t moreBits = (fraction & ((1 << reglen) - 1)) ? 0x0001 : 0x0000;
if (nonZeroRemainder) moreBits = 0x0001;
// n+1 frac bit is 1. Need to check if another bit is 1 too, if not round to even
bits += (bits & 0x0001) | moreBits;
else {
if (reglen == 14) {
bitNPlusOne = bool(exp & 0x2);
moreBits = exp & 0x1;
exp = 0;
}
else if (reglen == 13) {
bitNPlusOne = bool(exp & 0x1);
exp >>= 1;
}
if (frac32 > 0) {
fraction = 0;
moreBits = 0x1;
}
}
if (nonZeroRemainder) moreBits = 0x1;
bits = uint32_t(regime) | uint32_t(exp) | uint32_t(fraction);
if (bitNPlusOne) bits += (bits & 0x1) | moreBits;
}
return bits;
}
Expand Down
38 changes: 38 additions & 0 deletions include/universal/verification/test_case.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,44 @@ namespace sw { namespace universal {
return (reference == c) ? 0 : 1; // return 1 to indicate 1 test failure
}

template<typename TestType>
void TestWithValues(double da, double db, TestCaseOperator _operator) {
std::string op;
TestType a, b, c;
double dc;
a = da;
b = db;
switch (_operator) {
case TestCaseOperator::ADD:
c = a + b;
dc = da + db;
op = " + ";
break;
case TestCaseOperator::SUB:
c = a - b;
dc = da - db;
op = " - ";
break;
case TestCaseOperator::MUL:
c = a * b;
dc = da * db;
op = " * ";
break;
case TestCaseOperator::DIV:
c = a / b;
dc = da / db;
op = " / ";
break;
default:
std::cout << "Unknown operator: exiting\n";
return;
}
ReportBinaryOperation(a, "/", b, c);
TestType ref(dc);
ReportBinaryOperation(a, "/", b, ref);
if (c != ref) std::cout << "FAIL\n";
}

template<typename TestType>
void ReportValue(const TestType& a, const std::string& label = "", unsigned labelWidth = 20) {
std::cout << std::setw(labelWidth) << label << " : " << to_binary(a, true) << " : " << a << '\n';
Expand Down
15 changes: 12 additions & 3 deletions include/universal/verification/test_suite.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
// for number systems that do not have a math library.
//#include <universal/verification/test_suite_random.hpp>

namespace sw {
namespace universal {

// test triviality of an arithmetic type, trivially constructible, copyable, copy assignable
template<typename TestType>
void ReportTrivialityOfType() {
std::string testType = sw::universal::type_tag(TestType());
Expand All @@ -43,10 +47,11 @@ void ReportTrivialityOfType() {
std::cout << (isTriviallyCopyAssignable ? testType + std::string(" is trivially copy-assignable") : testType + std::string(" failed trivially copy-assignable: FAIL")) << '\n';
}

template<typename Real>
void ArithmeticOperators(Real a, Real b) {
// test the arithmetic operators on a test type
template<typename TestType>
void ArithmeticOperators(TestType a, TestType b) {
using namespace sw::universal;
Real c;
TestType c;

c = a + b;
ReportBinaryOperation(a, "+", b, c);
Expand Down Expand Up @@ -79,3 +84,7 @@ void ArithmeticOperators(Real a, Real b) {
b = 1; ++b;
ReportUnaryOperation("()++", a, b);
}


}
} // namespace sw::universal
64 changes: 26 additions & 38 deletions static/posit/specialized/posit_16_2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
// Configure the posit template environment
// first: enable fast specialized posit<16,2>
//#define POSIT_FAST_SPECIALIZATION
#define POSIT_FAST_POSIT_16_1 1
#define POSIT_FAST_POSIT_16_2 1
// second: enable posit arithmetic exceptions
#define POSIT_THROW_ARITHMETIC_EXCEPTION 1
Expand All @@ -21,26 +20,10 @@
#include <universal/verification/posit_test_suite.hpp>
#endif

void TestWithValues(double av, double bv) {
using namespace sw::universal;
posit<16, 2> a, b, c;
a = av;
b = bv;
c = a / b;
ReportBinaryOperation(a, "/", b, c);
double da = double(a);
double db = double(b);
double dc = da / db;
// ReportBinaryOperation(da, "/", db, dc);
posit<16, 2> ref(dc);
ReportBinaryOperation(a, "/", b, ref);
if (c != ref) std::cout << "FAIL\n";
}

// Standard posit with nbits = 16 have es = 2 exponent bit.

// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override
#define MANUAL_TESTING 1
#define MANUAL_TESTING 0
// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity
// It is the responsibility of the regression test to organize the tests in a quartile progression.
//#undef REGRESSION_LEVEL_OVERRIDE
Expand Down Expand Up @@ -84,26 +67,19 @@ try {

#if MANUAL_TESTING

TestWithValues(-9.0390625, -0.0225372314453125);
TestWithValues(1.1368683772161602974e-13, 8.5265128291212022305e-14);
using TestType = posit<16, 2>;
TestWithValues<TestType>(-9.0390625, -0.0225372314453125, TestCaseOperator::DIV);
TestWithValues<TestType>(1.1368683772161602974e-13, 8.5265128291212022305e-14, TestCaseOperator::DIV);
/*
-0.3614501953125 /= -281474976710656 != 2.2204460492503130808e-16 golden reference is 8.8817841970012523234e-16
0b1.01.10.01110010001 /= 0b1.11111111111110.0. != 0b0.00000000000001.0. golden reference is 0b0.00000000000001.1.
*/
TestWithValues(-0.3614501953125, -281474976710656);

nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_IPA, 100), tag, "+= (native) ");
nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_IPS, 100), tag, "-= (native) ");
nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_IPM, 100), tag, "*= (native) ");
nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_IPD, 100), tag, "/= (native) ");

goto epilog;

std::cout << "Exhaustive tests" << std::endl;
nrOfFailedTestCases += ReportTestResult(VerifyDivision <nbits, es>(reportTestCases), tag, "div (native) ");
nrOfFailedTestCases += ReportTestResult(VerifyMultiplication<nbits, es>(reportTestCases), tag, "mul (native) ");
nrOfFailedTestCases += ReportTestResult(VerifySubtraction <nbits, es>(reportTestCases), tag, "sub (native) ");
nrOfFailedTestCases += ReportTestResult(VerifyAddition <nbits, es>(reportTestCases), tag, "add (native) ");
TestWithValues<TestType>(-0.3614501953125, -281474976710656, TestCaseOperator::DIV);
/*
1.3877787807814456755e-17 /= -0.004917144775390625 != -8.8817841970012523234e-16 golden reference is -3.5527136788005009294e-15
0b0.000000000000001.. /= 0b1.001.00.0100001001 != 0b1.00000000000001.1. golden reference is 0b1.0000000000001.00.
*/
TestWithValues<TestType>(1.3877787807814456755e-17, -0.004917144775390625, TestCaseOperator::DIV);

{
posit<16, 2> a, b, c;
Expand All @@ -130,6 +106,19 @@ try {
testLogicOperators(b, a);
}

nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_IPA, 100), tag, "+= (native) ");
nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_IPS, 100), tag, "-= (native) ");
nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_IPM, 100), tag, "*= (native) ");
nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_IPD, 100), tag, "/= (native) ");

goto epilog; // skip the exhaustive tests

std::cout << "Exhaustive tests" << std::endl;
nrOfFailedTestCases += ReportTestResult(VerifyDivision <nbits, es>(reportTestCases), tag, "div (native) ");
nrOfFailedTestCases += ReportTestResult(VerifyMultiplication<nbits, es>(reportTestCases), tag, "mul (native) ");
nrOfFailedTestCases += ReportTestResult(VerifySubtraction <nbits, es>(reportTestCases), tag, "sub (native) ");
nrOfFailedTestCases += ReportTestResult(VerifyAddition <nbits, es>(reportTestCases), tag, "add (native) ");

epilog:
ReportTestSuiteResults(test_suite, nrOfFailedTestCases);
return EXIT_SUCCESS; // ignore failures
Expand Down Expand Up @@ -158,7 +147,6 @@ try {
test = "is positive";
nrOfFailedTestCases += ReportCheck(tag, test, p.ispos());

RND_TEST_CASES = 1024;
nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_ADD, RND_TEST_CASES), tag, "addition ");
nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_SUB, RND_TEST_CASES), tag, "subtraction ");
nrOfFailedTestCases += ReportTestResult(VerifyBinaryOperatorThroughRandoms<nbits, es>(reportTestCases, OPCODE_MUL, RND_TEST_CASES), tag, "multiplication");
Expand All @@ -181,9 +169,9 @@ try {
// conversion tests
std::cout << "Assignment/conversion tests\n";
nrOfFailedTestCases += ReportTestResult( VerifyIntegerConversion <nbits, es>(reportTestCases), tag, "integer assign (native) ");
// FAIL = 0.25003 did not convert to 0.250061 instead it yielded 0.25 raw 0b0.01.0.000000000000
// FAIL = 0.99994 did not convert to 0.999878 instead it yielded 1 raw 0b0.10.0.000000000000
// posit<16, 1> float assign(native) FAIL 2 failed test cases
// FAIL = 0.06251519627 did not convert to 0.06253051758 instead it yielded 0.0625 raw 0b0.01.00.00000000000
// FAIL = 0.9998789296 did not convert to 0.9997558594 instead it yielded 1 raw 0b0.10.00.00000000000
// posit< 16, 2> float assign(native) FAIL 2 failed test cases
// nrOfFailedTestCases += ReportTestResult( VerifyConversion <nbits, es>(true), tag, "float assign (native) ");

RND_TEST_CASES = 1024 * 1024;
Expand Down

0 comments on commit baf347a

Please sign in to comment.