Specifically, when constructed off a string I wasn't checking for a leading '-' sign.
That's kind of important.
Also 'e' notations will probably have to be included at some point.
I am really bad at this...
int dp = 0;
int end = 0;
+ bool negate = str[0] == '-';
+ if (negate)
+ {
+ dp++;
+ end++;
+ }
while (str[dp] != '\0' && str[dp] != '.')
{
++dp;
while (str[end] != '\0')
++end;
ParanoidNumber m(1);
- for (int i = dp-1; i >= 0; --i)
+ for (int i = dp-1; i >= negate; --i)
{
ParanoidNumber b(str[i]-'0');
b*=m;
b*=n;
this->operator+=(b);
}
+
+ if (negate)
+ Negate();
+
+ #ifdef PARANOID_COMPARE_EPSILON
+ double d = strtod(str.c_str(), NULL);
+ CompareForSanity(d, d);
+ #endif
}
ParanoidNumber & ParanoidNumber::operator=(const ParanoidNumber & a)
return true;
}
+void ParanoidNumber::Negate()
+{
+ swap(m_next[ADD], m_next[SUBTRACT]);
+ m_value = -m_value;
+}
+
#ifdef PARANOID_USE_ARENA
void * ParanoidNumber::operator new(size_t s)
// Define to compare all ops against double ops and check within epsilon
#define PARANOID_COMPARE_EPSILON 1e-6
-#define CompareForSanity(...) this->ParanoidNumber::CompareForSanityEx(__func__, __FILE__, __LINE__, __VA_ARGS__)
+#define CompareForSanity(...) ParanoidNumber::CompareForSanityEx(__func__, __FILE__, __LINE__, __VA_ARGS__)
namespace IPDF
{
m_next[i].push_back(new ParanoidNumber(*next)); // famous last words...
}
}
+ #ifdef PARANOID_COMPARE_EPSILON
+ CompareForSanity(cpy.Digit(), cpy.Digit());
+ #endif
//assert(SanityCheck());
}
// None of these are actually const
- 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<(const ParanoidNumber & a) const {return Digit() < a.Digit();}
+ bool operator<=(const ParanoidNumber & a) const {return Digit() <= a.Digit();}
+ bool operator>(const ParanoidNumber & a) const {return Digit() > a.Digit();}
+ bool operator>=(const ParanoidNumber & a) const {return Digit() >= a.Digit();}
+ bool operator==(const ParanoidNumber & a) const {return Digit() == a.Digit();}
+ bool operator!=(const ParanoidNumber & a) const {return Digit() != a.Digit();}
ParanoidNumber operator-() const
{
- ParanoidNumber neg(0);
- neg -= *this;
+ ParanoidNumber neg(*this);
+ neg.Negate();
+ #ifdef PARANOID_COMPARE_EPSILON
+ neg.CompareForSanity(-Digit(), Digit());
+ #endif
return neg;
}
+ void Negate();
+
+
ParanoidNumber operator+(const ParanoidNumber & a) const
{
ParanoidNumber result(*this);
- a.SanityCheck();
result += a;
+ #ifdef PARANOID_COMPARE_EPSILON
+ result.CompareForSanity(Digit()+a.Digit(), a.Digit());
+ #endif
return result;
}
ParanoidNumber operator-(const ParanoidNumber & a) const
{
ParanoidNumber result(*this);
result -= a;
+ #ifdef PARANOID_COMPARE_EPSILON
+ result.CompareForSanity(Digit()-a.Digit(), a.Digit());
+ #endif
return result;
}
ParanoidNumber operator*(const ParanoidNumber & a) const
{
ParanoidNumber result(*this);
result *= a;
- if (!result.SanityCheck())
- {
- Fatal("Blargh");
- }
+ #ifdef PARANOID_COMPARE_EPSILON
+ result.CompareForSanity(Digit()*a.Digit(), a.Digit());
+ #endif
return result;
}
ParanoidNumber operator/(const ParanoidNumber & a) const
{
ParanoidNumber result(*this);
result /= a;
+ #ifdef PARANOID_COMPARE_EPSILON
+ result.CompareForSanity(Digit()/a.Digit(), a.Digit());
+ #endif
return result;
}
DebugRealInfo();
unsigned failures = 0;
+ Real acumulate(0);
+ double dacumulate = 0;
for (unsigned i = 0; i < TEST_CASES; ++i)
{
//Debug("Test %u of %u", i, TEST_CASES);
Warn("a = b = %f should be %f, a before op was %f", Double(a), da, Double(abeforeop));
}
+ if (NotEqual(Double(-a), -da))
+ {
+ failures++;
+ Warn("-a = %f should be %f, a before op was %f", Double(-a), -da, Double(abeforeop));
+ }
+
+ if (NotEqual(Double(Sqrt(a)), Sqrt(da)))
+ {
+ failures++;
+ Warn("Sqrt(a) = %f should be %f, a before op was %f", Double(Sqrt(a)), Sqrt(da), Double(abeforeop));
+ }
+
+ if (NotEqual(Double(a), da))
+ {
+ failures++;
+ Warn("a = %f, should be %f, a before ops was %f", Double(a), da, Double(abeforeop));
+ }
+
+ switch (rand() % 4)
+ {
+ case 0:
+ acumulate += a;
+ dacumulate += da;
+ break;
+ case 1:
+ acumulate -= a;
+ dacumulate -= da;
+ break;
+ case 2:
+ acumulate *= a;
+ dacumulate *= da;
+ break;
+ case 3:
+ acumulate /= a;
+ dacumulate /= da;
+ break;
+ }
+ if (NotEqual(Double(acumulate), dacumulate))
+ {
+ Warn("Accumulated result %.30lf vs %.30lf is wrong", Double(acumulate), dacumulate);
+ failures++;
+ }
+
if (failures > old_failures)
{
Error("%u failures on case %u da = %f, db = %f, a = %f, b = %f, aa = %f, bb = %f", failures-old_failures, i, da, db, Double(a), Double(b), Double(aa), Double(bb));
Debug("\tStrings are a = %s, b = %s, aa = %s, bb = %s", a.Str().c_str(), b.Str().c_str(), aa.Str().c_str(), bb.Str().c_str());
#endif
}
+
}
- Debug("Completed %u test cases with total of %u operations, %u failures", TEST_CASES, 12*TEST_CASES, failures);
+ Debug("Completed %u test cases with total of %u operations, %u failures", TEST_CASES, 18*TEST_CASES, failures);
Debug("Total accumulated difference between Real and Double operations was %f", g_totalerror);
+ Debug("Real: %.40lf", Double(acumulate));
+ Debug("Doub: %.40lf", dacumulate);
+ Debug("Diff: %.40lf", Double(acumulate) - dacumulate);
}