X-Git-Url: https://git.ucc.asn.au/?p=ipdf%2Fcode.git;a=blobdiff_plain;f=src%2Fparanoidnumber.h;h=9e63a23371b853291d278164b88e922957bf59cb;hp=77a8d441caa24f7cabbc7225df390ece5b512a53;hb=3837f6a4e6ade33b9c57b1207f9f0774212c29b5;hpb=bb659698bba26042232c038065b7edaa72541f61 diff --git a/src/paranoidnumber.h b/src/paranoidnumber.h index 77a8d44..9e63a23 100644 --- a/src/paranoidnumber.h +++ b/src/paranoidnumber.h @@ -7,6 +7,8 @@ #include #include "log.h" #include +#include +#include #define PARANOID_DIGIT_T float // we could theoretically replace this with a template // but let's not do that... @@ -22,15 +24,8 @@ namespace IPDF (op == DIVIDE) ? MULTIPLY : (op == NOP) ? NOP : NOP); } - inline Optype AdjacentOp(Optype op) - { - return ((op == ADD) ? MULTIPLY : - (op == SUBTRACT) ? DIVIDE : - (op == MULTIPLY) ? ADD : - (op == DIVIDE) ? SUBTRACT : - (op == NOP) ? NOP : NOP); - } + inline char OpChar(int op) { static char opch[] = {'+','-','*','/'}; @@ -76,63 +71,48 @@ namespace IPDF public: typedef PARANOID_DIGIT_T digit_t; - ParanoidNumber(digit_t value=0) : m_value(value) + ParanoidNumber(digit_t value=0) : m_value(value), m_cached_result(value) { Construct(); } - ParanoidNumber(const ParanoidNumber & cpy) : m_value(cpy.m_value) + ParanoidNumber(const ParanoidNumber & cpy) : m_value(cpy.m_value), m_cached_result(cpy.m_cached_result) { Construct(); for (int i = 0; i < NOP; ++i) { - if (cpy.m_next[i] != NULL) - m_next[i] = new ParanoidNumber(*(cpy.m_next[i])); + for (auto next : cpy.m_next[i]) + m_next[i].push_back(new ParanoidNumber(*next)); } } ParanoidNumber(const char * str); - ParanoidNumber(const std::string & str) : ParanoidNumber(str.c_str()) {Construct();} + ParanoidNumber(const std::string & str) : ParanoidNumber(str.c_str()) {} virtual ~ParanoidNumber(); inline void Construct() { - for (int i = 0; i < NOP; ++i) - m_next[i] = NULL; g_count++; } template T Convert() const; - template T AddTerms(T value = T(0)) const; - template T MultiplyFactors(T value = T(1)) const; - template T Head() const {return (m_op == SUBTRACT) ? T(-m_value) : T(m_value);} - + digit_t GetFactors(); + digit_t GetTerms(); + - - - double ToDouble() const {return Convert();} - float ToFloat() const {return Convert();} - digit_t Digit() const {return Convert();} + double ToDouble() {return (double)Digit();} + digit_t Digit(); bool Floating() const { - for (int i = 0; i < NOP; ++i) - { - if (m_next[i] != NULL) - return false; - } - return true; + return NoFactors() && NoTerms(); } bool Sunken() const {return !Floating();} // I could not resist... - bool Pure(Optype op) const - { - if (op == ADD || op == SUBTRACT) - return (m_next[MULTIPLY] == NULL && m_next[DIVIDE] == NULL); - return (m_next[ADD] == NULL && m_next[SUBTRACT] == NULL); - } + bool NoFactors() const {return (m_next[MULTIPLY].size() == 0 && m_next[DIVIDE].size() == 0);} + bool NoTerms() const {return (m_next[ADD].size() == 0 && m_next[SUBTRACT].size() == 0);} ParanoidNumber & operator+=(const ParanoidNumber & a); ParanoidNumber & operator-=(const ParanoidNumber & a); @@ -140,17 +120,19 @@ namespace IPDF ParanoidNumber & operator/=(const ParanoidNumber & a); ParanoidNumber & operator=(const ParanoidNumber & a); - - ParanoidNumber * Operation(ParanoidNumber * b, Optype op, ParanoidNumber ** parent = NULL); + ParanoidNumber * OperationTerm(ParanoidNumber * b, Optype op, ParanoidNumber ** merge_point = NULL, Optype * mop = NULL); + ParanoidNumber * OperationFactor(ParanoidNumber * b, Optype op, ParanoidNumber ** merge_point = NULL, Optype * mop = NULL); + ParanoidNumber * TrivialOp(ParanoidNumber * b, Optype op); + ParanoidNumber * Operation(ParanoidNumber * b, Optype op, ParanoidNumber ** merge_point = NULL, Optype * mop = NULL); bool Simplify(Optype op); + bool FullSimplify(); - - bool operator<(const ParanoidNumber & a) const {return ToDouble() < a.ToDouble();} - bool operator<=(const ParanoidNumber & a) const {return this->operator<(a) || this->operator==(a);} - bool operator>(const ParanoidNumber & a) const {return !(this->operator<=(a));} - bool operator>=(const ParanoidNumber & a) const {return !(this->operator<(a));} - bool operator==(const ParanoidNumber & a) const {return ToDouble() == a.ToDouble();} - bool operator!=(const ParanoidNumber & a) const {return !(this->operator==(a));} + bool operator<(ParanoidNumber & a) {return ToDouble() < a.ToDouble();} + bool operator<=(ParanoidNumber & a) {return this->operator<(a) || this->operator==(a);} + bool operator>(ParanoidNumber & a) {return !(this->operator<=(a));} + bool operator>=(ParanoidNumber & a) {return !(this->operator<(a));} + bool operator==(ParanoidNumber & a) {return ToDouble() == a.ToDouble();} + bool operator!=(ParanoidNumber & a) {return !(this->operator==(a));} ParanoidNumber operator+(const ParanoidNumber & a) const { @@ -179,7 +161,25 @@ namespace IPDF std::string Str() const; - + ParanoidNumber * CopyTerms() + { + ParanoidNumber * copy = new ParanoidNumber(*this); + copy->m_value = 0; + copy->Simplify(ADD); + copy->Simplify(SUBTRACT); + return copy; + } + + ParanoidNumber * CopyFactors() + { + ParanoidNumber * copy = new ParanoidNumber(*this); + copy->m_value = 1; + copy->Simplify(MULTIPLY); + copy->Simplify(DIVIDE); + return copy; + } + + static int64_t Paranoia() {return g_count;} std::string PStr() const; @@ -193,69 +193,37 @@ namespace IPDF digit_t m_value; Optype m_op; - ParanoidNumber * m_next[4]; // Next by Operation + std::vector m_next[4]; + digit_t m_cached_result; + bool m_cache_valid; }; + + -template -T ParanoidNumber::AddTerms(T value) const -{ - ParanoidNumber * add = m_next[ADD]; - ParanoidNumber * sub = m_next[SUBTRACT]; - while (add != NULL && sub != NULL) - { - value += add->m_value * add->MultiplyFactors(); - value -= sub->m_value * sub->MultiplyFactors(); - add = add->m_next[ADD]; - sub = sub->m_next[SUBTRACT]; - } - while (add != NULL) - { - value += add->m_value * add->MultiplyFactors(); - add = add->m_next[ADD]; - } - while (sub != NULL) - { - value -= sub->m_value * sub->MultiplyFactors(); - sub = sub->m_next[SUBTRACT];; - } - return value; -} template -T ParanoidNumber::MultiplyFactors(T value) const +T ParanoidNumber::Convert() const { - ParanoidNumber * mul = m_next[MULTIPLY]; - ParanoidNumber * div = m_next[DIVIDE]; - while (mul != NULL && div != NULL) - { - value *= (mul->m_value + mul->AddTerms()); - value /= (div->m_value + div->AddTerms()); - mul = mul->m_next[MULTIPLY]; - div = div->m_next[DIVIDE]; - } - while (mul != NULL) + if (!isnan(m_cached_result)) + return (T)m_cached_result; + T value(m_value); + for (auto mul : m_next[MULTIPLY]) { - value *= (mul->m_value + mul->AddTerms()); - mul = mul->m_next[MULTIPLY]; + value *= mul->Convert(); } - while (div != NULL) + for (auto div : m_next[DIVIDE]) { - value /= (div->m_value + div->AddTerms()); - div = div->m_next[DIVIDE]; + value /= div->Convert(); } + for (auto add : m_next[ADD]) + value += add->Convert(); + for (auto sub : m_next[SUBTRACT]) + value -= sub->Convert(); return value; } -template -T ParanoidNumber::Convert() const -{ - return MultiplyFactors(m_value) + AddTerms(0); -} - - - } #endif //_PARANOIDNUMBER_H