Tester for exploring the mapping of a float to a real
[ipdf/code.git] / src / tests / represent.cpp
diff --git a/src/tests/represent.cpp b/src/tests/represent.cpp
new file mode 100644 (file)
index 0000000..2fb524a
--- /dev/null
@@ -0,0 +1,125 @@
+#include "main.h"
+#include "real.h"
+#include <cmath>
+#include <cassert>
+#include <list>
+
+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 <unsigned EMAX, unsigned PREC, unsigned BASE = 2> 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 <int EMAX, int PREC, int BASE = 2> 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<uint8_t, Real> Pear;
+       list<Pear> space;
+
+       for (uint8_t a = 0x00; a < 0xFF; ++a)
+       {
+               Real x = BitsToReal<2,4>(&a);
+               space.push_back(pair<uint8_t, Real>(a, x));
+       }
+       space.sort([=](const Pear & a, const Pear & b){return a.second < b.second;});
+       Real prev;
+       for (list<Pear>::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;        
+       }
+}

UCC git Repository :: git.ucc.asn.au