[poincare] Create DecimalNode, DecimalReference

This commit is contained in:
Émilie Feral
2018-08-03 16:42:09 +02:00
parent 5a1c75b43c
commit 2c5c14f0ab
3 changed files with 305 additions and 254 deletions

View File

@@ -1,50 +1,78 @@
#ifndef POINCARE_DECIMAL_H
#define POINCARE_DECIMAL_H
#include <poincare/static_hierarchy.h>
#include <poincare/integer.h>
namespace Poincare {
/* A decimal as 0.01234 is stored that way:
* - m_mantissa = 1234
* - m_exponent = -2
* - bool m_negative = false
* - int m_exponent = -2
* - int m_numberOfDigitsInMantissa = 1
* - native_uint_t m_mantissa[] = { 1234 }
*/
class Decimal : public StaticHierarchy<0> {
class DecimalNode : public NumberNode {
public:
static int exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative);
static Integer mantissa(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative);
Decimal(Integer mantissa, int exponent);
template <typename T> Decimal(T f);
int exponent() const { return m_exponent; }
Integer mantissa() const { return m_mantissa; }
// Expression subclassing
Type type() const override;
int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
Sign sign() const override { return m_mantissa.isNegative() ? Sign::Negative : Sign::Positive; }
constexpr static int k_maxExponentLength = 4;
private:
constexpr static double k_biggestMantissaFromDouble = 999999999999999;
constexpr static int k_maxDoubleExponent = 308;
/* Comparison */
void setValue(native_uint_t * mantissaDigits, size_t mantissaSize, int exponent, bool negative);
NaturalIntegerPointer mantissa() const;
// TreeNode
size_t size() const override { return sizeof(DecimalNode); }
#if TREE_LOG
const char * description() const override { return "Decimal"; }
#endif
// Properties
Type type() const override { return Type::Decimal; }
Sign sign() const override { return m_negative ? Sign::Negative : Sign::Positive; }
// Approximation
EvaluationReference<float> approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override {
return templatedApproximate<float>();
}
EvaluationReference<double> approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override {
return templatedApproximate<double>();
}
// Comparison
int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override;
/* Layout */
bool needsParenthesisWithParent(SerializableNode * parentNode) const override;
LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
/* Simplification */
// Simplification
ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override;
ExpressionReference shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override;
/* Evaluation */
EvaluationReference<float> approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, angleUnit); }
EvaluationReference<double> approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<double>(context, angleUnit); }
template<typename T> EvaluationReference<T> templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const;
int convertToText(char * buffer, int bufferSize, Preferences::PrintFloatMode mode, int numberOfSignificantDigits) const;
// Layout
bool needsParenthesisWithParent(SerializableNode * parentNode) const override;
LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override;
private:
// Worst case is -1.2345678901234E-1000
constexpr static int k_maxBufferSize = PrintFloat::k_numberOfStoredSignificantDigits+1+1+1+1+4+1;
Integer m_mantissa;
int convertToText(char * buffer, int bufferSize, Preferences::PrintFloatMode mode, int numberOfSignificantDigits) const;
template<typename T> EvaluationReference<T> templatedApproximate() const;
bool m_negative;
int m_exponent;
size_t m_numberOfDigitsInMantissa;
native_uint_t m_mantissa[0];
};
class DecimalReference : public NumberReference {
friend class Number;
public:
static int exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative);
DecimalReference(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative, int exponent);
constexpr static int k_maxExponentLength = 4;
private:
DecimalReference(TreeNode * n) : NumberReference(n) {}
template <typename T> DecimalReference(T f);
DecimalReference(IntegerReference m, int e);
DecimalReference(size_t size) : NumberReference() {
TreeNode * node = TreePool::sharedPool()->createTreeNode<DecimalNode>(size);
m_identifier = node->identifier();
}
};
}

View File

@@ -142,4 +142,4 @@ private:
}
#endif
#endif

View File

@@ -1,6 +1,8 @@
#include <poincare/decimal.h>
#include <poincare/rational.h>
#include <poincare/opposite.h>
#include <poincare/infinity.h>
#include <poincare/layout_engine.h>
#include <poincare/ieee754.h>
#include <assert.h>
#include <ion.h>
@@ -9,7 +11,227 @@
namespace Poincare {
int Decimal::exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative) {
void removeZeroAtTheEnd(IntegerReference * i) {
if (i->isZero()) {
return;
}
IntegerReference base = IntegerReference(10);
IntegerDivisionReference d = IntegerReference::Division(*i, base);
while (d.remainder.isZero()) {
*i = d.quotient;
d = IntegerReference::Division(*i, base);
}
}
void DecimalNode::setValue(native_uint_t * mantissaDigits, size_t mantissaSize, int exponent, bool negative) {
m_negative = negative;
m_exponent = exponent;
m_numberOfDigitsInMantissa = mantissaSize;
memcpy(m_mantissa, mantissaDigits, mantissaSize*sizeof(native_uint_t));
}
NaturalIntegerPointer DecimalNode::mantissa() const {
return NaturalIntegerPointer((native_uint_t *)m_mantissa, m_numberOfDigitsInMantissa);
}
int DecimalNode::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const {
assert(e->type() == Type::Decimal);
const DecimalNode * other = static_cast<const DecimalNode *>(e);
if (m_negative && !other->m_negative) {
return -1;
}
if (!m_negative && other->m_negative) {
return 1;
}
assert(m_negative == other->m_negative);
int unsignedComparison = 0;
if (m_exponent < other->m_exponent) {
unsignedComparison = -1;
} else if (m_exponent > other->m_exponent) {
unsignedComparison = 1;
} else {
assert(m_exponent == other->m_exponent);
NaturalIntegerPointer m = mantissa();
NaturalIntegerPointer otherM = other->mantissa();
unsignedComparison = NaturalIntegerAbstract::ucmp(&m, &otherM);
}
return ((int)sign())*unsignedComparison;
}
ExpressionReference DecimalNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) {
ExpressionReference e = ExpressionNode::shallowReduce(context, angleUnit);
if (e.node() != this) {
return e;
}
ExpressionReference reference(this);
NaturalIntegerPointer m = mantissa();
IntegerReference numerator(&m);
removeZeroAtTheEnd(&numerator);
int numberOfDigits = IntegerReference::NumberOfBase10Digits(numerator);
IntegerReference denominator(1);
if (m_exponent >= numberOfDigits-1) {
numerator = IntegerReference::Multiplication(numerator, IntegerReference::Power(IntegerReference(10), IntegerReference(m_exponent-numberOfDigits+1)));
} else {
denominator = IntegerReference::Power(IntegerReference(10), IntegerReference(numberOfDigits-1-m_exponent));
}
// Do not reduce decimal to rational if the exponent is too big or too small.
if (numerator.isInfinity()) {
assert(!denominator.isInfinity());
return InfinityReference(m_negative);
}
if (denominator.isInfinity()) {
assert(!denominator.isInfinity());
return RationalReference(0);
}
numerator.setNegative(m_negative);
return RationalReference(numerator, denominator);
}
ExpressionReference DecimalNode::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) {
ExpressionReference reference(this);
if (m_negative) {
m_negative = false;
return OppositeReference(reference);
}
return reference;
}
bool DecimalNode::needsParenthesisWithParent(SerializableNode * parentNode) const {
if (!m_negative) {
return false;
}
Type types[] = {Type::Addition, Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Division, Type::Power, Type::Factorial};
return static_cast<ExpressionNode *>(parentNode)->isOfType(types, 7);
}
LayoutRef DecimalNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
char buffer[k_maxBufferSize];
int numberOfChars = convertToText(buffer, k_maxBufferSize, floatDisplayMode, numberOfSignificantDigits);
return LayoutEngine::createStringLayout(buffer, numberOfChars);
}
int DecimalNode::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return convertToText(buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits);
}
int DecimalNode::convertToText(char * buffer, int bufferSize, Preferences::PrintFloatMode mode, int numberOfSignificantDigits) const {
if (bufferSize == 0) {
return -1;
}
buffer[bufferSize-1] = 0;
int currentChar = 0;
if (currentChar >= bufferSize-1) { return bufferSize-1; }
if (mantissa().isZero()) {
buffer[currentChar++] = '0';
buffer[currentChar] = 0;
return currentChar;
}
int exponent = m_exponent;
char tempBuffer[PrintFloat::k_numberOfStoredSignificantDigits+1];
// Round the integer if m_mantissa > 10^numberOfSignificantDigits-1
NaturalIntegerPointer m = mantissa();
IntegerReference mantissaRef(&m);
int numberOfDigitsInMantissa = IntegerReference::NumberOfBase10Digits(mantissaRef);
if (numberOfDigitsInMantissa > numberOfSignificantDigits) {
IntegerDivisionReference d = IntegerReference::Division(mantissaRef, IntegerReference((int64_t)std::pow(10.0, numberOfDigitsInMantissa - numberOfSignificantDigits)));
mantissaRef = d.quotient;
if (IntegerReference::NaturalOrder(d.remainder, IntegerReference((int64_t)(5.0*std::pow(10.0, numberOfDigitsInMantissa-numberOfSignificantDigits-1)))) >= 0) {
mantissaRef = IntegerReference::Addition(mantissaRef, IntegerReference(1));
// if 9999 was rounded to 10000, we need to update exponent and mantissa
if (IntegerReference::NumberOfBase10Digits(mantissaRef) > numberOfSignificantDigits) {
exponent++;
mantissaRef = IntegerReference::Division(mantissaRef, IntegerReference(10)).quotient;
}
}
removeZeroAtTheEnd(&mantissaRef);
}
if (m_negative) {
buffer[currentChar++] = '-';
if (currentChar >= bufferSize-1) { return bufferSize-1; }
}
int mantissaLength = mantissaRef.writeTextInBuffer(tempBuffer, PrintFloat::k_numberOfStoredSignificantDigits+1, mode, numberOfSignificantDigits);
if (strcmp(tempBuffer, "inf") == 0) {
currentChar += strlcpy(buffer+currentChar, tempBuffer, bufferSize-currentChar);
return currentChar;
}
/* We force scientific mode if the number of digits before the dot is superior
* to the number of significant digits (ie with 4 significant digits,
* 12345 -> 1.235E4 or 12340 -> 1.234E4). */
bool forceScientificMode = mode == Preferences::PrintFloatMode::Scientific || exponent >= numberOfSignificantDigits;
int numberOfRequiredDigits = mantissaLength;
if (!forceScientificMode) {
numberOfRequiredDigits = mantissaLength > exponent ? mantissaLength : exponent;
numberOfRequiredDigits = exponent < 0 ? mantissaLength-exponent : numberOfRequiredDigits;
}
/* Case 0: Scientific mode. Three cases:
* - the user chooses the scientific mode
* - the exponent is too big compared to the number of significant digits, so
* we force the scientific mode to avoid inventing digits
* - the number would be too long if we print it as a natural decimal */
if (numberOfRequiredDigits > PrintFloat::k_numberOfStoredSignificantDigits || forceScientificMode) {
if (mantissaLength == 1) {
currentChar += strlcpy(buffer+currentChar, tempBuffer, bufferSize-currentChar);
} else {
currentChar++;
int decimalMarkerPosition = currentChar;
if (currentChar >= bufferSize-1) { return bufferSize-1; }
currentChar += strlcpy(buffer+currentChar, tempBuffer, bufferSize-currentChar);
buffer[decimalMarkerPosition-1] = buffer[decimalMarkerPosition];
buffer[decimalMarkerPosition] = '.';
}
if (exponent == 0) {
return currentChar;
}
if (currentChar >= bufferSize-1) { return bufferSize-1; }
buffer[currentChar++] = Ion::Charset::Exponent;
currentChar += IntegerReference(exponent).writeTextInBuffer(buffer+currentChar, bufferSize-currentChar, mode, numberOfSignificantDigits);
return currentChar;
}
/* Case 1: Decimal mode */
int deltaCharMantissa = exponent < 0 ? -exponent+1 : 0;
strlcpy(buffer+currentChar+deltaCharMantissa, tempBuffer, bufferSize-deltaCharMantissa-currentChar);
if (exponent < 0) {
for (int i = 0; i <= -exponent; i++) {
if (currentChar >= bufferSize-1) { return bufferSize-1; }
if (i == 1) {
buffer[currentChar++] = '.';
continue;
}
buffer[currentChar++] = '0';
}
}
currentChar += mantissaLength;
if (exponent >= 0 && exponent < mantissaLength-1) {
if (currentChar+1 >= bufferSize-1) { return bufferSize-1; }
int decimalMarkerPosition = m_negative ? exponent + 1 : exponent;
for (int i = currentChar-1; i > decimalMarkerPosition; i--) {
buffer[i+1] = buffer[i];
}
if (currentChar >= bufferSize-1) { return bufferSize-1; }
buffer[decimalMarkerPosition+1] = '.';
currentChar++;
}
if (exponent >= 0 && exponent > mantissaLength-1) {
int endMarkerPosition = m_negative ? exponent+1 : exponent;
for (int i = currentChar-1; i < endMarkerPosition; i++) {
if (currentChar+1 >= bufferSize-1) { return bufferSize-1; }
buffer[currentChar++] = '0';
}
}
if (currentChar >= bufferSize-1) { return bufferSize-1; }
buffer[currentChar] = 0;
return currentChar;
}
template<typename T> EvaluationReference<T> DecimalNode::templatedApproximate() const {
NaturalIntegerPointer m = mantissa();
T f = m.approximate<T>();
int numberOfDigits = NaturalIntegerAbstract::NumberOfBase10Digits(&m);
T result = f*std::pow((T)10.0, (T)(m_exponent-numberOfDigits+1));
return ComplexReference<T>(m_negative ? -result : result);
}
int DecimalReference::exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative) {
int base = 10;
int exp = 0;
for (int i = 0; i < exponentLength; i++) {
@@ -42,238 +264,39 @@ int Decimal::exponent(const char * integralPart, int integralPartLength, const c
return exp;
}
void removeZeroAtTheEnd(Integer & i) {
if (i.isZero()) {
return;
}
Integer base = Integer(10);
IntegerDivision d = Integer::Division(i, base);
while (d.remainder.isZero()) {
i = d.quotient;
d = Integer::Division(i, base);
}
}
Integer Decimal::mantissa(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative) {
Integer zero = Integer(0);
Integer base = Integer(10);
Integer numerator = Integer(integralPart, negative);
DecimalReference::DecimalReference(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative, int exponent) {
IntegerReference zero(0);
IntegerReference base(10);
IntegerReference numerator(integralPart, integralPartLength, negative);
for (int i = 0; i < fractionalPartLength; i++) {
numerator = Integer::Multiplication(numerator, base);
numerator = Integer::Addition(numerator, Integer(*fractionalPart-'0'));
numerator = IntegerReference::Multiplication(numerator, base);
numerator = IntegerReference::Addition(numerator, IntegerReference(*fractionalPart-'0'));
fractionalPart++;
}
return numerator;
}
Decimal::Decimal(Integer mantissa, int exponent) :
m_mantissa(mantissa),
m_exponent(exponent)
{
*this = DecimalReference(numerator, exponent);
}
template <typename T>
Decimal::Decimal(T f) {
m_exponent = IEEE754<T>::exponentBase10(f);
int64_t mantissaf = std::round((double)f * std::pow((double)10.0, (double)(-m_exponent+PrintFloat::k_numberOfStoredSignificantDigits+1)));
m_mantissa = Integer(mantissaf);
DecimalReference::DecimalReference(T f) {
assert(!std::isnan(f) && !std::isinf(f));
int exp = IEEE754<T>::exponentBase10(f);
int64_t mantissaf = std::round((double)f * std::pow((double)10.0, (double)(-exp+PrintFloat::k_numberOfStoredSignificantDigits+1)));
IntegerReference m(mantissaf);
*this= DecimalReference(IntegerReference(mantissaf), exp);
}
Expression::Type Decimal::type() const {
return Type::Decimal;
DecimalReference::DecimalReference(IntegerReference m, int e) {
if (m.isAllocationFailure()) {
*this = DecimalReference(ExpressionNode::FailedAllocationStaticNode());
return;
}
*this = DecimalReference(sizeof(DecimalNode)+sizeof(native_uint_t)*m.numberOfDigits());
if (!node()->isAllocationFailure()) {
static_cast<DecimalNode *>(node())->setValue(m.typedNode()->digits(), m.typedNode()->numberOfDigits(), e, m.isNegative());
}
}
Expression * Decimal::clone() const {
return new Decimal(m_mantissa, m_exponent);
}
template<typename T> EvaluationReference<T> Decimal::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const {
T m = m_mantissa.approximate<T>();
int numberOfDigits = Integer::numberOfDigitsWithoutSign(m_mantissa);
return new Complex<T>(m*std::pow((T)10.0, (T)(m_exponent-numberOfDigits+1)));
}
int Decimal::convertToText(char * buffer, int bufferSize, Preferences::PrintFloatMode mode, int numberOfSignificantDigits) const {
if (bufferSize == 0) {
return -1;
}
buffer[bufferSize-1] = 0;
int currentChar = 0;
if (currentChar >= bufferSize-1) { return bufferSize-1; }
if (m_mantissa.isZero()) {
buffer[currentChar++] = '0';
buffer[currentChar] = 0;
return currentChar;
}
int exponent = m_exponent;
char tempBuffer[PrintFloat::k_numberOfStoredSignificantDigits+1];
// Round the integer if m_mantissa > 10^numberOfSignificantDigits-1
Integer absMantissa = m_mantissa;
absMantissa.setNegative(false);
int numberOfDigitsInMantissa = Integer::numberOfDigitsWithoutSign(m_mantissa);
if (numberOfDigitsInMantissa > numberOfSignificantDigits) {
IntegerDivision d = Integer::Division(absMantissa, Integer((int64_t)std::pow(10.0, numberOfDigitsInMantissa - numberOfSignificantDigits)));
absMantissa = d.quotient;
if (Integer::NaturalOrder(d.remainder, Integer((int64_t)(5.0*std::pow(10.0, numberOfDigitsInMantissa-numberOfSignificantDigits-1)))) >= 0) {
absMantissa = Integer::Addition(absMantissa, Integer(1));
// if 9999 was rounded to 10000, we need to update exponent and mantissa
if (Integer::numberOfDigitsWithoutSign(absMantissa) > numberOfSignificantDigits) {
exponent++;
absMantissa = Integer::Division(absMantissa, Integer(10)).quotient;
}
}
removeZeroAtTheEnd(absMantissa);
}
int mantissaLength = absMantissa.writeTextInBuffer(tempBuffer, PrintFloat::k_numberOfStoredSignificantDigits+1);
if (strcmp(tempBuffer, "undef") == 0) {
currentChar = strlcpy(buffer, tempBuffer, bufferSize);
return currentChar;
}
/* We force scientific mode if the number of digits before the dot is superior
* to the number of significant digits (ie with 4 significant digits,
* 12345 -> 1.235E4 or 12340 -> 1.234E4). */
bool forceScientificMode = mode == Preferences::PrintFloatMode::Scientific || exponent >= numberOfSignificantDigits;
int numberOfRequiredDigits = mantissaLength;
if (!forceScientificMode) {
numberOfRequiredDigits = mantissaLength > exponent ? mantissaLength : exponent;
numberOfRequiredDigits = exponent < 0 ? mantissaLength-exponent : numberOfRequiredDigits;
}
if (currentChar >= bufferSize-1) { return bufferSize-1; }
if (m_mantissa.isNegative()) {
buffer[currentChar++] = '-';
if (currentChar >= bufferSize-1) { return bufferSize-1; }
}
/* Case 0: Scientific mode. Three cases:
* - the user chooses the scientific mode
* - the exponent is too big compared to the number of significant digits, so
* we force the scientific mode to avoid inventing digits
* - the number would be too long if we print it as a natural decimal */
if (numberOfRequiredDigits > PrintFloat::k_numberOfStoredSignificantDigits || forceScientificMode) {
if (mantissaLength == 1) {
currentChar += strlcpy(buffer+currentChar, tempBuffer, bufferSize-currentChar);
} else {
currentChar++;
int decimalMarkerPosition = currentChar;
if (currentChar >= bufferSize-1) { return bufferSize-1; }
currentChar += strlcpy(buffer+currentChar, tempBuffer, bufferSize-currentChar);
buffer[decimalMarkerPosition-1] = buffer[decimalMarkerPosition];
buffer[decimalMarkerPosition] = '.';
}
if (exponent == 0) {
return currentChar;
}
if (currentChar >= bufferSize-1) { return bufferSize-1; }
buffer[currentChar++] = Ion::Charset::Exponent;
currentChar += Integer(exponent).writeTextInBuffer(buffer+currentChar, bufferSize-currentChar);
return currentChar;
}
/* Case 1: Decimal mode */
int deltaCharMantissa = exponent < 0 ? -exponent+1 : 0;
strlcpy(buffer+currentChar+deltaCharMantissa, tempBuffer, bufferSize-deltaCharMantissa-currentChar);
if (exponent < 0) {
for (int i = 0; i <= -exponent; i++) {
if (currentChar >= bufferSize-1) { return bufferSize-1; }
if (i == 1) {
buffer[currentChar++] = '.';
continue;
}
buffer[currentChar++] = '0';
}
}
currentChar += mantissaLength;
if (exponent >= 0 && exponent < mantissaLength-1) {
if (currentChar+1 >= bufferSize-1) { return bufferSize-1; }
int decimalMarkerPosition = m_mantissa.isNegative() ? exponent + 1 : exponent;
for (int i = currentChar-1; i > decimalMarkerPosition; i--) {
buffer[i+1] = buffer[i];
}
if (currentChar >= bufferSize-1) { return bufferSize-1; }
buffer[decimalMarkerPosition+1] = '.';
currentChar++;
}
if (exponent >= 0 && exponent > mantissaLength-1) {
int endMarkerPosition = m_mantissa.isNegative() ? exponent+1 : exponent;
for (int i = currentChar-1; i < endMarkerPosition; i++) {
if (currentChar+1 >= bufferSize-1) { return bufferSize-1; }
buffer[currentChar++] = '0';
}
}
if (currentChar >= bufferSize-1) { return bufferSize-1; }
buffer[currentChar] = 0;
return currentChar;
}
int Decimal::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return convertToText(buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits);
}
bool Decimal::needParenthesisWithParent(const Expression * e) const {
if (sign() == Sign::Positive) {
return false;
}
Type types[] = {Type::Addition, Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Division, Type::Power, Type::Factorial};
return e->isOfType(types, 7);
}
LayoutRef Decimal::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
char buffer[k_maxBufferSize];
int numberOfChars = convertToText(buffer, k_maxBufferSize, floatDisplayMode, numberOfSignificantDigits);
return LayoutEngine::createStringLayout(buffer, numberOfChars);
}
ExpressionReference Decimal::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) {
Expression * e = Expression::shallowReduce(context, angleUnit);
if (e != this) {
return e;
}
// Do not reduce decimal to rational if the exponent is too big or too small.
if (m_exponent > k_maxDoubleExponent || m_exponent < -k_maxDoubleExponent) {
return this; // TODO: return new Infinite() ? RationalReference(0) ?
}
Integer numerator = m_mantissa;
removeZeroAtTheEnd(numerator);
int numberOfDigits = Integer::numberOfDigitsWithoutSign(numerator);
Integer denominator = Integer(1);
if (m_exponent >= numberOfDigits-1) {
numerator = Integer::Multiplication(numerator, Integer::Power(Integer(10), Integer(m_exponent-numberOfDigits+1)));
} else {
denominator = Integer::Power(Integer(10), Integer(numberOfDigits-1-m_exponent));
}
return replaceWith(new Rational(numerator, denominator), true);
}
Expression * Decimal::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) {
if (m_mantissa.isNegative()) {
m_mantissa.setNegative(false);
Opposite * o = new Opposite(this, true);
return replaceWith(o, true);
}
return this;
}
int Decimal::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const {
assert(e->type() == Type::Decimal);
const Decimal * other = static_cast<const Decimal *>(e);
if (sign() == Sign::Negative && other->sign() == Sign::Positive) {
return -1;
}
if (sign() == Sign::Positive && other->sign() == Sign::Negative) {
return 1;
}
assert(sign() == other->sign());
int unsignedComparison = 0;
if (exponent() < other->exponent()) {
unsignedComparison = -1;
} else if (exponent() > other->exponent()) {
unsignedComparison = 1;
} else {
assert(exponent() == other->exponent());
unsignedComparison = Integer::NaturalOrder(mantissa(), other->mantissa());
}
return ((int)sign())*unsignedComparison;
}
template Decimal::Decimal(double);
template Decimal::Decimal(float);
template DecimalReference::DecimalReference(double);
template DecimalReference::DecimalReference(float);
}