X-Git-Url: https://git.ucc.asn.au/?p=ipdf%2Fcode.git;a=blobdiff_plain;f=src%2Ftests%2Frepresent.cpp;fp=src%2Ftests%2Frepresent.cpp;h=2fb524ad69d9a6be3ce9f7952225341ae216bc2d;hp=0000000000000000000000000000000000000000;hb=805dd6babc18f4e16c297f0c20487418d5aa6bd8;hpb=e24724d4c5a0c57be728b418a2d75d94fbe442a3 diff --git a/src/tests/represent.cpp b/src/tests/represent.cpp new file mode 100644 index 0000000..2fb524a --- /dev/null +++ b/src/tests/represent.cpp @@ -0,0 +1,125 @@ +#include "main.h" +#include "real.h" +#include +#include +#include + +using namespace std; +using namespace IPDF; + +/** + * This "tester" lets us construct Reals out of Floating Points with arbitrary sizes (but must be less than 64 bits currently) + * Eventually it will also go the other way + * This is originally for conceptual understanding but will ultimately become useful later on. + */ + + +/** + * From http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer + */ +long CountBits(long n) +{ + unsigned int c; // c accumulates the total bits set in v + for (c = 0; n; c++) + n &= n - 1; // clear the least significant bit set + return c; +} + +/** + * Converts data represented as an (se, e, m, sm) floating point number to a Real. + * se = sign of exponent (1 bit) + * e = exponent (EMAX bits) + * m = mantissa (PREC bits) + * sm = sign of mantissa (1 bit) + * Total 1+EMAX+PREC+1 must not exceed 64 (at least, for the moment) + */ +template Real BitsToReal(void * data) +{ + if (PREC + EMAX > 62) // we need 1 bit for the sign of the exponent, 1 bit for the sign + Fatal("Can't do more than 62 bits (asked for %d + %d = %d)", PREC, EMAX, PREC+EMAX); + + // memcpy needs a whole number of bytes + // This means we need to do tricky bit shifting to get rid of parts of the exp/mantissa that overlap + size_t ebytes = ceil(double(EMAX+1.0) / 8.0); + size_t mbytes = ceil(double(PREC+1.0)/8.0); + size_t moffset = floor(double(EMAX+1.0) / 8.0); // offset to start of mantissa (nearest byte) + //Debug("ebytes %d, mbytes %d, moffset %d", ebytes, mbytes, moffset); + + // Get the exponent and its sign + uint64_t exponent = 0L; + bool exp_sign = false; + + memcpy(&exponent, data, ebytes); // Copy exponent + //Debug("exponent + garbage: %x", exponent); + exp_sign = (1L << (8*ebytes-1)) & exponent; + exponent &= ~(1L << (8*ebytes-1)); // mask out the sign + //Debug("exponent - masked sign: %x", exponent); + exponent = exponent >> (PREC+1); // shift out the extra bits (part of mantissa) + assert(CountBits(exponent) <= EMAX); //TODO: Remove once sure it actually works //TODO: Need more reliable sanity checks probably + + // Get the mantissa and its sign + uint64_t mantissa = 0L; + bool sign = false; + + memcpy(&mantissa, ((uint8_t*)(data) + moffset), mbytes); // copy data + //Debug("mantissa + garbage: %x", mantissa); + sign = mantissa & (1L); // get sign + mantissa = mantissa >> 1; // discard sign + mantissa = (mantissa << (8*sizeof(mantissa) - PREC)) >> (8*sizeof(mantissa) - PREC); + assert(CountBits(mantissa) <= PREC); + + /* + Debug("EMAX %u, PREC %u, BASE %u", EMAX, PREC, BASE); + Debug("EXP: %x", exponent); + Debug("MANTISSA: %x", mantissa); + Debug("EXP_SIGN: %x", (uint8_t)exp_sign); + Debug("MANTISSA_SIGN: %x", (uint8_t)sign); + */ + + Real Q = (exp_sign) ? pow(Real(BASE), -Real(exponent)) : pow(Real(BASE), Real(exponent)); + Real x = Real(mantissa) * Q; + return (sign) ? -x : x; +} + +/** + * Performs the inverse of BitsToReal + */ +template void BitsFromReal(const Real & x, void * data) +{ + bool sign; + uint64_t mantissa; + uint64_t exponent; + if (PREC + EMAX > 62) + Fatal("Can't do more than 62 bits (asked for %d + %d = %d)", PREC, EMAX, PREC+EMAX); + + //TODO: Implement + +} + + + +int main(int argc, char ** argv) +{ + printf("# Convert custom floats to a Real\n"); + printf("# a\thex(a)\tReal(a)\tdelta(last2)\n"); + + typedef pair Pear; + list space; + + for (uint8_t a = 0x00; a < 0xFF; ++a) + { + Real x = BitsToReal<2,4>(&a); + space.push_back(pair(a, x)); + } + space.sort([=](const Pear & a, const Pear & b){return a.second < b.second;}); + Real prev; + for (list::iterator i = space.begin(); i != space.end(); ++i) + { + printf("%u\t%x\t%f", i->first, i->first, Float(i->second)); + if (i != space.begin()) + { + printf("\t%f\n", Float(i->second - prev)); + } + prev = i->second; + } +}