12 * This "tester" lets us construct Reals out of Floating Points with arbitrary sizes (but must be less than 64 bits currently)
13 * Eventually it will also go the other way
14 * This is originally for conceptual understanding but will ultimately become useful later on.
20 * From http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer
22 long CountBits(long n)
24 unsigned int c; // c accumulates the total bits set in v
26 n &= n - 1; // clear the least significant bit set
31 * Converts data represented as an (s, e, m) floating point number to a Real.
32 * Now actually correct for floats bigger than 8 bits!
33 * Now with 100% less memcpy and 100% more pointer arithmetic!
34 * Now with IEEE style encodings! (How many flops does it take to represent a float this way? TOO MANY!)
35 * Still probably breaks if you are not using an x86 based processor
37 * e = exponent (IEEE ``offset'' encoding)
38 * m = mantissa (IEEE encoding)
40 template <size_t EMAX, size_t PREC, size_t BASE = 2> Real BitsToReal(void * data)
42 if (PREC + EMAX > 62) // we need 1 bit for the sign of the exponent, 1 bit for the sign
43 Fatal("Can't do more than 62 bits (asked for %d + %d = %d)", PREC, EMAX, PREC+EMAX);
45 size_t mbytes = ceil(double(PREC)/8.0);
46 size_t mtrunc = floor(double(PREC)/8.0);
47 uint64_t mantissa = 0L;
48 uint8_t * c = (uint8_t*)(data);
49 for (size_t i = 0; i < mbytes; ++i)
51 mantissa |= *(c++) << (i*8);
53 mantissa &= ~(~0L << PREC);
55 size_t ebytes = ceil(double(EMAX)/8.0);
56 uint64_t exponent = *(c-1) & (~0L << (PREC-8*mtrunc));
57 for (size_t i = 0; i < ebytes; ++i)
59 exponent |= *(c++) << (i+1)*8;
61 exponent = exponent >> (PREC-8*mtrunc);
62 bool sign = exponent & (1LL << EMAX);
63 exponent &= ~(~0L << EMAX);
65 // Floats are defined by
66 // x = (-1)^s * m * B^{e}
68 // In IEEE things get a little crazy though, the mantissa is stored reversed and the digits are summed indexed using negative powers of 2 (not positive)
69 // So to conform with IEEE can't just treat the mantissa as an unsigned integer
71 // Calculate the actual mantissa from the IEEE style encoding of the mantissa (sigh)
72 // This is obviously horribly inefficient but I guess that encoding not designed for ... whatever it is I'm doing here
73 Real M = (exponent != 0);
74 for (size_t i = 1; i < PREC; ++i)
76 if ((mantissa >> PREC-i) & 1)
77 M += Real(1) / powl(BASE, i);
81 //Debug("Mantissa: %x = %lf", mantissa, Float(M));
82 //Debug("Exponent: %x = %u => %lf", exponent, exponent, Float(Real(exponent + 1) - Real(1LL << (EMAX-1))));
83 //Debug("Sign: %x = %u", sign, sign);
86 Real x = M * powl(Real(BASE), Real(exponent + 1)-Real(1LL << (EMAX-1)));
87 return (sign) ? -x : x;
91 * Modifies fraction to contain the fractional part of x
92 * Returns position of the first '1' bit
94 size_t Fraction(Real x, uint64_t & fraction)
96 x = abs(x) - (uint64_t)(abs(x));
99 for (size_t i = 0; i < 8*sizeof(fraction); ++i)
104 offset = (offset == 0) ? i : offset;
105 fraction |= (1LL << (8*sizeof(fraction)-1-i));
115 * Copy mantissa and exponent into data
117 template <size_t EMAX, size_t PREC, size_t BASE = 2> void BitsFromRepr(bool sign, uint64_t mantissa, uint64_t exponent, void * data)
119 uint8_t * c = (uint8_t*)(data);
121 for (i = 0; i < PREC; ++i)
123 *c |= ((mantissa >> i) & 1) << (i%8);
129 for (; i < PREC+EMAX; ++i)
131 *c |= ((exponent >> (i-PREC)) & 1) << (i%8);
137 *c |= (sign << (i%8));
144 * Performs the inverse of BitsToReal
146 * It chooses the normalised representation
148 template <size_t EMAX, size_t PREC, size_t BASE = 2> void BitsFromReal(Real x, void * data)
150 if (PREC + EMAX > 62)
151 Fatal("Can't do more than 62 bits (asked for %d + %d = %d)", PREC, EMAX, PREC+EMAX);
153 uint64_t integer = (uint64_t)(abs(x));
154 uint64_t fraction = 0LL;
155 const size_t max_bits = 8*sizeof(uint64_t);
157 x = abs(x) - integer;
159 size_t fraction_leading_zeroes = max_bits;
160 for (size_t i = 0; i < max_bits; ++i)
165 if (fraction_leading_zeroes > i)
166 fraction_leading_zeroes = i;
168 fraction |= (1LL << (max_bits-1-i));
174 uint64_t mantissa = 0LL;
175 int64_t biased_exponent = 0LL;
177 // Combine integer and fraction into mantissa
180 //Debug("0. %lx (%d)", fraction, fraction_leading_zeroes);
181 // Mantissa must have leading '1'; shift to get leading 1, then shift back to mantissa position
182 mantissa = (fraction << fraction_leading_zeroes) >> (max_bits - PREC);
183 biased_exponent -= fraction_leading_zeroes;
184 // If the unbiased exponent would be negative use a denormalised number instead
185 if (biased_exponent < -(1LL << (EMAX-1))+1)
187 mantissa = mantissa >> (-(1LL << (EMAX-1))+1 - biased_exponent);
188 biased_exponent = -(1LL << (EMAX-1))+1;
194 size_t integer_leading_zeroes = 0;
195 for (integer_leading_zeroes = 0; integer_leading_zeroes < max_bits; ++integer_leading_zeroes)
197 if ((integer >> (max_bits-1-integer_leading_zeroes)) & 1LL)
200 //Debug("%.16lx . %.16lx (%li, %li)", integer,fraction, integer_leading_zeroes, fraction_leading_zeroes);
202 mantissa = (integer << (integer_leading_zeroes)); // shift integer part
203 mantissa |= (fraction >> (max_bits-integer_leading_zeroes)); // append the fraction after it
204 //Debug("%.16lx (%.16lx << %i)", mantissa, fraction, (fraction_leading_zeroes - max_bits + integer_leading_zeroes));
205 mantissa = mantissa >> (max_bits - PREC); // shift back to the mantissa position
206 biased_exponent = (max_bits - integer_leading_zeroes); // calculate exponent
209 // If the unbiased exponent would be non-zero, the IEEE has the leading 1 as implied; remove it and decrease exponent to compensate
210 if (biased_exponent != -(1LL << (EMAX-1))+1)
212 mantissa &= ~(1LL << max_bits - PREC);
213 mantissa = mantissa << 1;
214 biased_exponent -= 1;
217 uint64_t exponent = (uint64_t)(biased_exponent + (1LL << (EMAX-1))-1); // offset the exponent
221 Real M = (exponent != 0);
222 for (size_t i = 1; i < PREC; ++i)
224 if ((mantissa >> PREC-i) & 1)
225 M += Real(1) / powl(BASE, i);
228 Debug("Exponent: %lx %lu -> %li", exponent, exponent, biased_exponent);
229 Debug("Mantissa: %lx -> %f", mantissa, Float(M));
230 Debug("Both: %lx", mantissa | (exponent << (PREC)));
232 // Now copy the bits in
233 BitsFromRepr<EMAX, PREC, BASE>(sign, mantissa, exponent, data);
239 int main(int argc, char ** argv)
241 printf("# Convert custom floats to a Real\n");
242 printf("# a\thex(a)\tReal(a)\tdelta(last2)\n");
244 typedef pair<uint16_t, Real> Pear;
246 uint16_t a0 = 0x0000;
247 for (uint16_t a = a0; a < 0xFFFF; ++a)
249 Real x = BitsToReal<5,10>(&a);
250 uint16_t b = 0; BitsFromReal<5,10>(x, &b);
251 Real y = BitsToReal<5,10>(&b);
254 Fatal("%x -> %lf -> %x -> %lf", a, Float(x), b, Float(y));
256 space.push_back(Pear(a, x));
258 space.sort([=](const Pear & a, const Pear & b){return a.second < b.second;});
260 for (list<Pear>::iterator i = space.begin(); i != space.end(); ++i)
262 printf("%u\t%.2x\t%.20lf", i->first, i->first, Float(i->second));
263 if (i != space.begin())
264 printf("\t%f", Float(i->second - prev));