|
- //
- // Lol Engine
- //
- // Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the Do What The Fuck You Want To
- // Public License, Version 2, as published by Sam Hocevar. See
- // http://sam.zoy.org/projects/COPYING.WTFPL for more details.
- //
-
- #if defined HAVE_CONFIG_H
- # include "config.h"
- #endif
-
- #include <cstring>
- #include <cstdio>
-
- #include "core.h"
-
- using namespace std;
-
- namespace lol
- {
-
- real::real(float f) { *this = (double)f; }
- real::real(int i) { *this = (double)i; }
- real::real(unsigned int i) { *this = (double)i; }
-
- real::real(double d)
- {
- union { double d; uint64_t x; } u = { d };
-
- uint32_t sign = (u.x >> 63) << 31;
- uint32_t exponent = (u.x << 1) >> 53;
-
- switch (exponent)
- {
- case 0x00:
- m_signexp = sign;
- break;
- case 0x7ff:
- m_signexp = sign | 0x7fffffffu;
- break;
- default:
- m_signexp = sign | (exponent + (1 << 30) - (1 << 10));
- break;
- }
-
- m_mantissa[0] = u.x >> 36;
- m_mantissa[1] = u.x >> 20;
- m_mantissa[2] = u.x >> 4;
- m_mantissa[3] = u.x << 12;
- memset(m_mantissa + 4, 0, sizeof(m_mantissa) - 4 * sizeof(m_mantissa[0]));
- }
-
- real::operator float() const { return (float)(double)(*this); }
- real::operator int() const { return (int)(double)(*this); }
- real::operator unsigned int() const { return (unsigned int)(double)(*this); }
-
- real::operator double() const
- {
- union { double d; uint64_t x; } u;
-
- /* Get sign */
- u.x = m_signexp >> 31;
- u.x <<= 11;
-
- /* Compute new exponent */
- uint32_t exponent = (m_signexp << 1) >> 1;
- int e = (int)exponent - (1 << 30) + (1 << 10);
-
- if (e < 0)
- u.x <<= 52;
- else if (e >= 0x7ff)
- {
- u.x |= 0x7ff;
- u.x <<= 52;
- }
- else
- {
- u.x |= e;
-
- /* Store mantissa if necessary */
- u.x <<= 16;
- u.x |= m_mantissa[0];
- u.x <<= 16;
- u.x |= m_mantissa[1];
- u.x <<= 16;
- u.x |= m_mantissa[2];
- u.x <<= 4;
- u.x |= m_mantissa[3] >> 12;
- /* Rounding */
- u.x += (m_mantissa[3] >> 11) & 1;
- }
-
- return u.d;
- }
-
- real real::operator -() const
- {
- real ret = *this;
- ret.m_signexp ^= 0x80000000u;
- return ret;
- }
-
- real real::operator +(real const &x) const
- {
- if (x.m_signexp << 1 == 0)
- return *this;
-
- /* Ensure both arguments are positive. Otherwise, switch signs,
- * or replace + with -. */
- if (m_signexp >> 31)
- return -(-*this + -x);
-
- if (x.m_signexp >> 31)
- return *this - (-x);
-
- /* Ensure *this is the larger exponent (no need to be strictly larger,
- * as in subtraction). Otherwise, switch. */
- if ((m_signexp << 1) < (x.m_signexp << 1))
- return x + *this;
-
- real ret;
-
- int e1 = m_signexp - (1 << 30) + 1;
- int e2 = x.m_signexp - (1 << 30) + 1;
-
- int bigoff = (e1 - e2) / (sizeof(uint16_t) * 8);
- int off = e1 - e2 - bigoff * (sizeof(uint16_t) * 8);
-
- if (bigoff > BIGITS)
- return *this;
-
- ret.m_signexp = m_signexp;
-
- uint32_t carry = 0;
- for (int i = BIGITS; i--; )
- {
- carry += m_mantissa[i];
- if (i - bigoff >= 0)
- carry += x.m_mantissa[i - bigoff] >> off;
-
- if (i - bigoff > 0)
- carry += (x.m_mantissa[i - bigoff - 1] << (16 - off)) & 0xffffu;
- else if (i - bigoff == 0)
- carry += 0x0001u << (16 - off);
-
- ret.m_mantissa[i] = carry;
- carry >>= 16;
- }
-
- /* Renormalise in case we overflowed the mantissa */
- if (carry)
- {
- carry--;
- for (int i = 0; i < BIGITS; i++)
- {
- uint16_t tmp = ret.m_mantissa[i];
- ret.m_mantissa[i] = (carry << 15) | (tmp >> 1);
- carry = tmp & 0x0001u;
- }
- ret.m_signexp++;
- }
-
- return ret;
- }
-
- real real::operator -(real const &x) const
- {
- if (x.m_signexp << 1 == 0)
- return *this;
-
- /* Ensure both arguments are positive. Otherwise, switch signs,
- * or replace - with +. */
- if (m_signexp >> 31)
- return -(-*this + x);
-
- if (x.m_signexp >> 31)
- return (*this) + (-x);
-
- /* Ensure *this is larger than x */
- if (*this < x)
- return -(x - *this);
-
- real ret;
-
- int e1 = m_signexp - (1 << 30) + 1;
- int e2 = x.m_signexp - (1 << 30) + 1;
-
- int bigoff = (e1 - e2) / (sizeof(uint16_t) * 8);
- int off = e1 - e2 - bigoff * (sizeof(uint16_t) * 8);
-
- if (bigoff > BIGITS)
- return *this;
-
- ret.m_signexp = m_signexp;
-
- int32_t carry = 0;
- for (int i = 0; i < bigoff; i++)
- {
- carry -= x.m_mantissa[BIGITS - i];
- carry = (carry & 0xffff0000u) | (carry >> 16);
- }
- carry -= x.m_mantissa[BIGITS - 1 - bigoff] & ((1 << off) - 1);
- carry /= (1 << off);
-
- for (int i = BIGITS; i--; )
- {
- carry += m_mantissa[i];
- if (i - bigoff >= 0)
- carry -= x.m_mantissa[i - bigoff] >> off;
-
- if (i - bigoff > 0)
- carry -= (x.m_mantissa[i - bigoff - 1] << (16 - off)) & 0xffffu;
- else if (i - bigoff == 0)
- carry -= 0x0001u << (16 - off);
-
- ret.m_mantissa[i] = carry;
- carry = (carry & 0xffff0000u) | (carry >> 16);
- }
-
- carry += 1;
-
- /* Renormalise if we underflowed the mantissa */
- if (carry == 0)
- {
- /* How much do we need to shift the mantissa? FIXME: this could
- * be computed above */
- off = 0;
- for (int i = 0; i < BIGITS; i++)
- {
- if (!ret.m_mantissa[i])
- {
- off += sizeof(uint16_t) * 8;
- continue;
- }
-
- for (uint16_t tmp = ret.m_mantissa[i]; tmp < 0x8000u; tmp <<= 1)
- off++;
- break;
- }
- if (off == BIGITS * sizeof(uint16_t) * 8)
- ret.m_signexp &= 0x80000000u;
- else
- {
- off++; /* Shift one more to get rid of the leading one */
- ret.m_signexp -= off;
-
- bigoff = off / (sizeof(uint16_t) * 8);
- off -= bigoff * sizeof(uint16_t) * 8;
-
- for (int i = 0; i < BIGITS; i++)
- {
- uint16_t tmp = 0;
- if (i + bigoff < BIGITS)
- tmp |= ret.m_mantissa[i + bigoff] << off;
- if (i + bigoff + 1 < BIGITS)
- tmp |= ret.m_mantissa[i + bigoff + 1] >> (16 - off);
- ret.m_mantissa[i] = tmp;
- }
- }
- }
-
- return ret;
- }
-
- real real::operator *(real const &x) const
- {
- real ret;
-
- if (m_signexp << 1 == 0 || x.m_signexp << 1 == 0)
- {
- ret = (m_signexp << 1 == 0) ? *this : x;
- ret.m_signexp ^= x.m_signexp & 0x80000000u;
- return ret;
- }
-
- ret.m_signexp = (m_signexp ^ x.m_signexp) & 0x80000000u;
- int e = (m_signexp & 0x7fffffffu) - (1 << 30) + 1
- + (x.m_signexp & 0x7fffffffu) - (1 << 30) + 1;
-
- /* Accumulate low order product; no need to store it, we just
- * want the carry value */
- uint64_t carry = 0;
- for (int i = 0; i < BIGITS; i++)
- {
- for (int j = 0; j < i + 1; j++)
- carry += (uint32_t)m_mantissa[BIGITS - 1 - j]
- * (uint32_t)x.m_mantissa[BIGITS - 1 + j - i];
- carry >>= 16;
- }
-
- for (int i = 0; i < BIGITS; i++)
- {
- for (int j = i + 1; j < BIGITS; j++)
- carry += (uint32_t)m_mantissa[BIGITS - 1 - j]
- * (uint32_t)x.m_mantissa[j - 1 - i];
-
- carry += m_mantissa[BIGITS - 1 - i];
- carry += x.m_mantissa[BIGITS - 1 - i];
- ret.m_mantissa[BIGITS - 1 - i] = carry & 0xffffu;
- carry >>= 16;
- }
-
- /* Renormalise in case we overflowed the mantissa */
- if (carry)
- {
- carry--;
- for (int i = 0; i < BIGITS; i++)
- {
- uint16_t tmp = ret.m_mantissa[i];
- ret.m_mantissa[i] = (carry << 15) | (tmp >> 1);
- carry = tmp & 0x0001u;
- }
- e++;
- }
-
- ret.m_signexp |= e + (1 << 30) - 1;
-
- return ret;
- }
-
- real real::operator /(real const &x) const
- {
- return *this * fres(x);
- }
-
- real &real::operator +=(real const &x)
- {
- real tmp = *this;
- return *this = tmp + x;
- }
-
- real &real::operator -=(real const &x)
- {
- real tmp = *this;
- return *this = tmp - x;
- }
-
- real &real::operator *=(real const &x)
- {
- real tmp = *this;
- return *this = tmp * x;
- }
-
- real &real::operator /=(real const &x)
- {
- real tmp = *this;
- return *this = tmp / x;
- }
-
- bool real::operator ==(real const &x) const
- {
- if ((m_signexp << 1) == 0 && (x.m_signexp << 1) == 0)
- return true;
-
- if (m_signexp != x.m_signexp)
- return false;
-
- return memcmp(m_mantissa, x.m_mantissa, sizeof(m_mantissa)) == 0;
- }
-
- bool real::operator !=(real const &x) const
- {
- return !(*this == x);
- }
-
- bool real::operator <(real const &x) const
- {
- /* Ensure both numbers are positive */
- if (m_signexp >> 31)
- return (x.m_signexp >> 31) ? -*this > -x : true;
-
- if (x.m_signexp >> 31)
- return false;
-
- /* Compare all relevant bits */
- if (m_signexp != x.m_signexp)
- return m_signexp < x.m_signexp;
-
- for (int i = 0; i < BIGITS; i++)
- if (m_mantissa[i] != x.m_mantissa[i])
- return m_mantissa[i] < x.m_mantissa[i];
-
- return false;
- }
-
- bool real::operator <=(real const &x) const
- {
- return !(*this > x);
- }
-
- bool real::operator >(real const &x) const
- {
- /* Ensure both numbers are positive */
- if (m_signexp >> 31)
- return (x.m_signexp >> 31) ? -*this < -x : false;
-
- if (x.m_signexp >> 31)
- return true;
-
- /* Compare all relevant bits */
- if (m_signexp != x.m_signexp)
- return m_signexp > x.m_signexp;
-
- for (int i = 0; i < BIGITS; i++)
- if (m_mantissa[i] != x.m_mantissa[i])
- return m_mantissa[i] > x.m_mantissa[i];
-
- return false;
- }
-
- bool real::operator >=(real const &x) const
- {
- return !(*this < x);
- }
-
- real fres(real const &x)
- {
- if (!(x.m_signexp << 1))
- {
- real ret = x;
- ret.m_signexp = x.m_signexp | 0x7fffffffu;
- ret.m_mantissa[0] = 0;
- return ret;
- }
-
- /* Use the system's float inversion to approximate 1/x */
- union { float f; uint32_t x; } u = { 1.0f }, v = { 1.0f };
- v.x |= (uint32_t)x.m_mantissa[0] << 7;
- v.x |= (uint32_t)x.m_mantissa[1] >> 9;
- v.f = 1.0 / v.f;
-
- real ret;
- ret.m_mantissa[0] = (v.x >> 7) & 0xffffu;
- ret.m_mantissa[1] = (v.x << 9) & 0xffffu;
-
- uint32_t sign = x.m_signexp & 0x80000000u;
- ret.m_signexp = sign;
-
- int exponent = (x.m_signexp & 0x7fffffffu) + 1;
- exponent = -exponent + (v.x >> 23) - (u.x >> 23);
- ret.m_signexp |= (exponent - 1) & 0x7fffffffu;
-
- /* Five steps of Newton-Raphson seems enough for 32-bigit reals. */
- real two = 2;
- ret = ret * (two - ret * x);
- ret = ret * (two - ret * x);
- ret = ret * (two - ret * x);
- ret = ret * (two - ret * x);
- ret = ret * (two - ret * x);
-
- return ret;
- }
-
- real sqrt(real const &x)
- {
- /* if zero, return x */
- if (!(x.m_signexp << 1))
- return x;
-
- /* if negative, return NaN */
- if (x.m_signexp >> 31)
- {
- real ret;
- ret.m_signexp = 0x7fffffffu;
- ret.m_mantissa[0] = 0xffffu;
- return ret;
- }
-
- /* Use the system's float inversion to approximate 1/sqrt(x). First
- * we construct a float in the [1..4[ range that has roughly the same
- * mantissa as our real. Its exponent is 0 or 1, depending on the
- * partity of x. The final exponent is 0, -1 or -2. We use the final
- * exponent and final mantissa to pre-fill the result. */
- union { float f; uint32_t x; } u = { 1.0f }, v = { 2.0f };
- v.x -= ((x.m_signexp & 1) << 23);
- v.x |= (uint32_t)x.m_mantissa[0] << 7;
- v.x |= (uint32_t)x.m_mantissa[1] >> 9;
- v.f = 1.0 / sqrtf(v.f);
-
- real ret;
- ret.m_mantissa[0] = (v.x >> 7) & 0xffffu;
- ret.m_mantissa[1] = (v.x << 9) & 0xffffu;
-
- uint32_t sign = x.m_signexp & 0x80000000u;
- ret.m_signexp = sign;
-
- int exponent = (x.m_signexp & 0x7fffffffu) - ((1 << 30) - 1);
- exponent = - (exponent / 2) + (v.x >> 23) - (u.x >> 23);
- ret.m_signexp |= (exponent + ((1 << 30) - 1)) & 0x7fffffffu;
-
- /* Five steps of Newton-Raphson seems enough for 32-bigit reals. */
- real three = 3;
- ret = ret * (three - ret * ret * x);
- ret.m_signexp--;
- ret = ret * (three - ret * ret * x);
- ret.m_signexp--;
- ret = ret * (three - ret * ret * x);
- ret.m_signexp--;
- ret = ret * (three - ret * ret * x);
- ret.m_signexp--;
- ret = ret * (three - ret * ret * x);
- ret.m_signexp--;
-
- return ret * x;
- }
-
- real fabs(real const &x)
- {
- real ret = x;
- ret.m_signexp &= 0x7fffffffu;
- return ret;
- }
-
- real exp(real const &x)
- {
- int square = 0;
-
- /* FIXME: this is slow. Find a better way to approximate exp(x) for
- * large values. */
- real tmp = x, one = 1.0;
- while (tmp > one)
- {
- tmp.m_signexp--;
- square++;
- }
-
- real ret = 1.0, fact = 1.0, xn = tmp;
-
- for (int i = 1; i < 100; i++)
- {
- fact *= (real)i;
- ret += xn / fact;
- xn *= tmp;
- }
-
- for (int i = 0; i < square; i++)
- ret = ret * ret;
-
- return ret;
- }
-
- real sin(real const &x)
- {
- real ret = 0.0, fact = 1.0, xn = x, x2 = x * x;
-
- for (int i = 1; ; i += 2)
- {
- real newret = ret + xn / fact;
- if (ret == newret)
- break;
- ret = newret;
- xn *= x2;
- fact *= (real)(-(i + 1) * (i + 2));
- }
-
- return ret;
- }
-
- real cos(real const &x)
- {
- real ret = 0.0, fact = 1.0, xn = 1.0, x2 = x * x;
-
- for (int i = 1; ; i += 2)
- {
- real newret = ret + xn / fact;
- if (ret == newret)
- break;
- ret = newret;
- xn *= x2;
- fact *= (real)(-i * (i + 1));
- }
-
- return ret;
- }
-
- void real::print(int ndigits) const
- {
- real const r1 = 1, r10 = 10;
- real x = *this;
-
- if (x.m_signexp >> 31)
- {
- printf("-");
- x = -x;
- }
-
- /* Normalise x so that mantissa is in [1..9.999] */
- int exponent = 0;
- if (x.m_signexp)
- {
- for (real div = r1, newdiv; true; div = newdiv)
- {
- newdiv = div * r10;
- if (x < newdiv)
- {
- x /= div;
- break;
- }
- exponent++;
- }
- for (real mul = 1, newx; true; mul *= r10)
- {
- newx = x * mul;
- if (newx >= r1)
- {
- x = newx;
- break;
- }
- exponent--;
- }
- }
-
- /* Print digits */
- for (int i = 0; i < ndigits; i++)
- {
- int digit = (int)x;
- printf("%i", digit);
- if (i == 0)
- printf(".");
- x -= real(digit);
- x *= r10;
- }
-
- /* Print exponent information */
- if (exponent < 0)
- printf("e-%i", -exponent);
- else if (exponent > 0)
- printf("e+%i", exponent);
-
- printf("\n");
- }
-
- } /* namespace lol */
|