#include extern "C" { #include #include #include #include } #include #include "layout/string_layout.h" #include namespace Poincare { static inline int max(int x, int y) { return (x>y ? x : y); } uint8_t log2(Integer::native_uint_t v) { constexpr int nativeUnsignedIntegerBitCount = 8*sizeof(Integer::native_uint_t); static_assert(nativeUnsignedIntegerBitCount < 256, "uint8_t cannot contain the log2 of a native_uint_t"); for (uint8_t i=0; i= '0' && *digits <= '9') { result = Multiplication(result, base); result = Addition(result, Integer(*digits-'0')); digits++; } } *this = std::move(result); m_negative = negative; #if 0 // Pilfer v's ivars m_numberOfDigits = result.m_numberOfDigits; if (result.usesImmediateDigit()) { m_digit = result.m_digit; } else { m_digits = result.m_digits; } // Zero-out v result.m_numberOfDigits = 0; if (result.usesImmediateDigit()) { result.m_digit = 0; } else { result.m_digits = NULL; } #endif } Integer::~Integer() { if (!usesImmediateDigit()) { assert(m_digits != nullptr); delete[] m_digits; } } Integer::Integer(Integer && other) { // Pilfer other's data if (other.usesImmediateDigit()) { m_digit = other.m_digit; } else { m_digits = other.m_digits; } m_numberOfDigits = other.m_numberOfDigits; m_negative = other.m_negative; // Reset other other.m_digit = 0; other.m_numberOfDigits = 1; other.m_negative = 0; } Integer& Integer::operator=(Integer && other) { if (this != &other) { // Release our ivars if (!usesImmediateDigit()) { assert(m_digits != nullptr); delete[] m_digits; } // Pilfer other's ivars if (other.usesImmediateDigit()) { m_digit = other.m_digit; } else { m_digits = other.m_digits; } m_numberOfDigits = other.m_numberOfDigits; m_negative = other.m_negative; // Reset other other.m_digit = 0; other.m_numberOfDigits = 1; other.m_negative = 0; } return *this; } // Expression subclassing Expression::Type Integer::type() const { return Type::Integer; } Expression * Integer::clone() const { native_uint_t * cloneDigits = new native_uint_t [m_numberOfDigits]; for (uint16_t i=0; itype() == Expression::Type::Integer); const Integer * other = static_cast(e); if (m_negative && !other->m_negative) { return -1; } if (!m_negative && other->m_negative) { return 1; } return sign(m_negative)*ucmp(*this, *other); } bool Integer::isEqualTo(const Integer & other) const { return (compareTo(&other) == 0); } bool Integer::isLowerThan(const Integer & other) const { return (compareTo(&other) < 0); } // Arithmetic Integer Integer::Addition(const Integer & a, const Integer & b) { return addition(a, b, false); } Integer Integer::Subtraction(const Integer & a, const Integer & b) { return addition(a, b, true); } Integer Integer::Multiplication(const Integer & a, const Integer & b) { assert(sizeof(double_native_uint_t) == 2*sizeof(native_uint_t)); uint16_t productSize = a.m_numberOfDigits + b.m_numberOfDigits; native_uint_t * digits = new native_uint_t [productSize]; memset(digits, 0, productSize*sizeof(native_uint_t)); double_native_uint_t carry = 0; for (uint16_t i=0; i1) { productSize--; /* At this point we could realloc m_digits to a smaller size. */ } return Integer(digits, productSize, a.m_negative != b.m_negative); } /*Integer Integer::Division(const Integer & a, const Integer & b) { return IntegerDivision(a, b).quotient(); } */ // Private methods /* WARNING: This constructor takes ownership of the digits array! */ Integer::Integer(const native_uint_t * digits, uint16_t numberOfDigits, bool negative) : m_numberOfDigits(numberOfDigits), m_negative(negative) { assert(digits != nullptr); if (numberOfDigits == 1) { m_digit = digits[0]; delete[] digits; } else { assert(numberOfDigits > 1); m_digits = digits; } } int8_t Integer::ucmp(const Integer & a, const Integer & b) { if (a.m_numberOfDigits < b.m_numberOfDigits) { return -1; } else if (a.m_numberOfDigits > b.m_numberOfDigits) { return 1; } for (uint16_t i = 0; i < a.m_numberOfDigits; i++) { // Digits are stored most-significant last native_uint_t aDigit = a.digit(a.m_numberOfDigits-i-1); native_uint_t bDigit = b.digit(b.m_numberOfDigits-i-1); if (aDigit < bDigit) { return -1; } else if (aDigit > bDigit) { return 1; } } return 0; } Integer Integer::usum(const Integer & a, const Integer & b, bool subtract, bool outputNegative) { uint16_t size = max(a.m_numberOfDigits, b.m_numberOfDigits); if (!subtract) { // Addition can overflow size += 1; } native_uint_t * digits = new native_uint_t [size]; bool carry = false; for (uint16_t i = 0; i= a.m_numberOfDigits ? 0 : a.digit(i)); native_uint_t bDigit = (i >= b.m_numberOfDigits ? 0 : b.digit(i)); native_uint_t result = (subtract ? aDigit - bDigit - carry : aDigit + bDigit + carry); digits[i] = result; carry = (subtract ? (aDigitresult)||(bDigit>result))); // There's been an underflow or overflow } while (digits[size-1] == 0 && size>1) { size--; // We could realloc digits to a smaller size. Probably not worth the trouble. } return Integer(digits, size, outputNegative); } Integer Integer::addition(const Integer & a, const Integer & b, bool inverseBNegative) { bool bNegative = (inverseBNegative ? !b.m_negative : b.m_negative); if (a.m_negative == bNegative) { return usum(a, b, false, a.m_negative); } else { /* The signs are different, this is in fact a subtraction * s = a+b = (abs(a)-abs(b) OR abs(b)-abs(a)) * 1/abs(a)>abs(b) : s = sign*udiff(a, b) * 2/abs(b)>abs(a) : s = sign*udiff(b, a) * sign? sign of the greater! */ if (ucmp(a, b) >= 0) { return usum(a, b, true, a.m_negative); } else { return usum(b, a, true, bNegative); } } } int Integer::identifier() const { assert(m_numberOfDigits > 0); int sign = m_negative ? -1 : 1; return sign*m_digits[0]; } /* Integer Integer::divide_by(const Integer &other) const { return IntegerDivision(*this, other).m_quotient; } Multiplication Integer::primeFactorization() const { Integer result = this; Integer i = 2; while (i 0) { set(i, occurrencesOfI); } i++; } } */ Evaluation * Integer::privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const { union { uint32_t uint_result; float float_result; }; assert(sizeof(float) == 4); /* We're generating an IEEE 754 compliant float. * Theses numbers are 32-bit values, stored as follow: * sign (1 bit) * exponent (8 bits) * mantissa (23 bits) * * We can tell that: * - the sign is going to be 0 for now, we only handle positive numbers * - the exponent is the length of our BigInt, in bits - 1 + 127; * - the mantissa is the beginning of our BigInt, discarding the first bit */ native_uint_t lastDigit = digit(m_numberOfDigits-1); uint8_t numberOfBitsInLastDigit = log2(lastDigit); bool sign = m_negative; uint8_t exponent = 126; /* if the exponent is bigger then 255, it cannot be stored as a uint8. Also, * the integer whose 2-exponent is bigger than 255 cannot be stored as a * float (IEEE 754 floating point). The approximation is thus INFINITY. */ if ((int)exponent + (m_numberOfDigits-1)*32 +numberOfBitsInLastDigit> 255) { return new Complex(Complex::Float(INFINITY)); } exponent += (m_numberOfDigits-1)*32; exponent += numberOfBitsInLastDigit; uint32_t mantissa = 0; mantissa |= (lastDigit << (32-numberOfBitsInLastDigit)); if (m_numberOfDigits >= 2) { native_uint_t beforeLastDigit = digit(m_numberOfDigits-2); mantissa |= (beforeLastDigit >> numberOfBitsInLastDigit); } if ((m_numberOfDigits==1) && (digit(0)==0)) { /* This special case for 0 is needed, because the current algorithm assumes * that the big integer is non zero, thus puts the exponent to 126 (integer * area), the issue is that when the mantissa is 0, a "shadow bit" is * assumed to be there, thus 126 0x000000 is equal to 0.5 and not zero. */ float result = m_negative ? -0.0f : 0.0f; return new Complex(Complex::Float(result)); } uint_result = 0; uint_result |= (sign << 31); uint_result |= (exponent << 23); uint_result |= (mantissa >> (32-23-1) & 0x7FFFFF); /* If exponent is 255 and the float is undefined, we have exceed IEEE 754 * representable float. */ if (exponent == 255 && isnan(float_result)) { return new Complex(Complex::Float(INFINITY)); } return new Complex(Complex::Float(float_result)); } Evaluation * Integer::privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const { union { uint64_t uint_result; double double_result; }; assert(sizeof(double) == 8); /* We're generating an IEEE 754 compliant double. * Theses numbers are 64-bit values, stored as follow: * sign (1 bit) * exponent (11 bits) * mantissa (52 bits) * * We can tell that: * - the exponent is the length of our BigInt, in bits - 1 + 1023; * - the mantissa is the beginning of our BigInt, discarding the first bit */ native_uint_t lastDigit = digit(m_numberOfDigits-1); uint8_t numberOfBitsInLastDigit = log2(lastDigit); bool sign = m_negative; uint16_t exponent = 1022; /* if the exponent is bigger then 2047, it cannot be stored as a uint11. Also, * the integer whose 2-exponent is bigger than 2047 cannot be stored as a * double (IEEE 754 double point). The approximation is thus INFINITY. */ if ((int)exponent + (m_numberOfDigits-1)*32 +numberOfBitsInLastDigit> 2047) { return new Complex(Complex::Float(INFINITY)); } exponent += (m_numberOfDigits-1)*32; exponent += numberOfBitsInLastDigit; uint64_t mantissa = 0; mantissa |= ((uint64_t)lastDigit << (64-numberOfBitsInLastDigit)); int digitIndex = 2; int numberOfBits = log2(lastDigit); while (m_numberOfDigits >= digitIndex) { lastDigit = digit(m_numberOfDigits-digitIndex); numberOfBits += 32; if (64 > numberOfBits) { mantissa |= ((uint64_t)lastDigit << (64-numberOfBits)); } else { mantissa |= ((uint64_t)lastDigit >> (numberOfBits-64)); } digitIndex++; } if ((m_numberOfDigits==1) && (digit(0)==0)) { /* This special case for 0 is needed, because the current algorithm assumes * that the big integer is non zero, thus puts the exponent to 126 (integer * area), the issue is that when the mantissa is 0, a "shadow bit" is * assumed to be there, thus 126 0x000000 is equal to 0.5 and not zero. */ float result = m_negative ? -0.0f : 0.0f; return new Complex(Complex::Float(result)); } uint_result = 0; uint_result |= ((uint64_t)sign << 63); uint_result |= ((uint64_t)exponent << 52); uint_result |= ((uint64_t)mantissa >> (64-52-1) & 0xFFFFFFFFFFFFF); /* If exponent is 2047 and the double is undefined, we have exceed IEEE 754 * representable double. */ if (exponent == 2047 && isnan(double_result)) { return new Complex(Complex::Float(INFINITY)); } return new Complex(Complex::Float(double_result)); } ExpressionLayout * Integer::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); /* If the integer is too long, this method may overflow the stack. * Experimentally, we can display at most integer whose number of digits is * around 7. However, to avoid crashing when the stack is already half full, * we decide not to display integers whose number of digits > 5. */ if (m_numberOfDigits > 5) { return new StringLayout("inf", 3); } char buffer[255]; Integer base = Integer(10); IntegerDivision d = IntegerDivision(*this, base); int size = 0; if (isEqualTo(Integer(0))) { buffer[size++] = '0'; } while (!d.remainder().isEqualTo(Integer(0)) && d.quotient().isEqualTo(Integer(0))) { assert(size<255); //TODO: malloc an extra buffer char c = char_from_digit(d.remainder().digit(0)); buffer[size++] = c; d = IntegerDivision(d.quotient(), base); } buffer[size] = 0; // Flip the string for (int i=0, j=size-1 ; i < j ; i++, j--) { char c = buffer[i]; buffer[i] = buffer[j]; buffer[j] = c; } return new StringLayout(buffer, size); } // Class IntegerDivision IntegerDivision::IntegerDivision(const Integer & numerator, const Integer & denominator) : m_quotient(Integer(0)), m_remainder(Integer(0)) { // FIXME: First, test if denominator is zero. if (numerator.isLowerThan(denominator)) { m_quotient = Integer(0); m_remainder = Integer::Addition(numerator, Integer(0)); // FIXME: This is a ugly way to bypass creating a copy constructor! return; } // Recursive case *this = IntegerDivision(numerator, Integer::Addition(denominator, denominator)); m_quotient = Integer::Addition(m_quotient, m_quotient); if (!(m_remainder.isLowerThan(denominator))) { m_remainder = Integer::Subtraction(m_remainder, denominator); m_quotient = Integer::Addition(m_quotient, Integer(1)); } } }