Merge branch 'master' of git.ucc.asn.au:/ipdf/code
[ipdf/code.git] / src / tests / paranoidtester.cpp
index 98c056d..47969b9 100644 (file)
@@ -13,7 +13,7 @@
 using namespace std;
 using namespace IPDF;
 
-string RandomNumberAsString(int max_digits = 12)
+string RandomNumberAsString(int max_digits = 3)
 {
        string result("");
        int digits = 1+(rand() % max_digits);
@@ -30,31 +30,219 @@ string RandomNumberAsString(int max_digits = 12)
        return result;
 }
 
-bool CloseEnough(double d, ParanoidNumber & p)
+bool CloseEnough(long double d, ParanoidNumber & p, long double eps = 1e-6)
 {
-       double pd = p.ToDouble();
+       long double pd = p.Convert<long double>();
                
        if (d == 0)
-               return fabs(pd) <= 1e-6;
-       return fabs((fabs(pd - d) / d)) <= 1e-6;
+               return fabs(pd) <= eps;
+       return fabs((fabs(pd - d) / d)) <= eps;
+}
+
+void TestOp(ParanoidNumber & p, double & d, Optype op, const double amount)
+{
+       string p0str(p.Str());
+       double p0 = p.ToDouble();
+       switch (op)
+       {
+               case ADD:
+                       p += amount;
+                       d += amount;
+                       break;
+               case SUBTRACT:
+                       p -= amount;
+                       d -= amount;
+                       break;
+               case MULTIPLY:
+                       p *= amount;
+                       d *= amount;
+                       break;
+               case DIVIDE:
+                       p /= amount;
+                       d /= amount;
+                       break;
+               default:
+                       break;
+       }
+       if (!CloseEnough(d, p))
+       {
+               Debug("%lf %c= %lf failed", p0, OpChar(op), amount);
+               Debug("%lf vs %lf", p.ToDouble(), d);
+               Debug("Before: {%s}\n", p0str.c_str());
+               Debug("After: {%s}\n", p.Str().c_str());
+               Fatal(":-(");
+       }
+
+}
+
+void TestAddSubIntegers(int max=100)
+{
+       Debug("Test add/sub integers 0 -> %i", max);
+       ParanoidNumber p;
+       double d(0);
+       for (int a = 0; a < max; ++a)
+       {
+               TestOp(p, d, ADD, a);
+               for (int b = 0; b < max; ++b)
+               {
+                       TestOp(p, d, SUBTRACT, b);
+               }
+               for (int b = 0; b < max; ++b)
+               {
+                       TestOp(p, d, ADD, b);
+               }
+       }
+       for (int a = 0; a < max; ++a)
+       {
+               TestOp(p, d, SUBTRACT, a);
+               for (int b = 0; b < max; ++b)
+               {
+                       TestOp(p, d, ADD, b);
+               }
+               for (int b = 0; b < max; ++b)
+               {
+                       TestOp(p, d, SUBTRACT, b);
+               }
+       }
+       Debug("PN Yields: %.40lf", p.ToDouble());
+       Debug("Doubles Yield: %.40lf", d);
+       Debug("Complete!");
+
+}
+
+void TestMulDivIntegers(int max=50)
+{
+       Debug("Test mul/div integers 1 -> %i", max);
+       ParanoidNumber p(1.0);
+       double d(1.0);
+       for (int a = 1; a < max; ++a)
+       {
+               TestOp(p, d, MULTIPLY, a);
+               for (int b = 1; b < max; ++b)
+               {
+                       TestOp(p, d, DIVIDE, b);
+               }
+               for (int b = 1; b < max; ++b)
+               {
+                       TestOp(p, d, MULTIPLY, b);
+               }
+       }
+       for (int a = 1; a < max; ++a)
+       {
+               TestOp(p, d, DIVIDE, a);
+               for (int b = 1; b < max; ++b)
+               {
+                       TestOp(p, d, MULTIPLY, b);
+               }
+               for (int b = 1; b < max; ++b)
+               {
+                       TestOp(p, d, DIVIDE, b);
+               }
+       }
+       Debug("PN Yields: %.40lf", p.ToDouble());
+       Debug("Doubles Yield: %.40lf", d);
+       Debug("Complete!");
+
+}
+
+void TestRandomisedOps(int test_cases = 1000, int ops_per_case = 1, int max_digits = 4)
+{
+       Debug("Test %i*%i randomised ops (max digits = %i)", test_cases, ops_per_case, max_digits);
+       long double eps = 1e-2; //* (1e4*ops_per_case);
+       for (int i = 0; i < test_cases; ++i)
+       {
+               string s = RandomNumberAsString(max_digits);
+               ParanoidNumber a(s);
+               
+               double da(a.ToDouble());                
+               for (int j = 1; j <= ops_per_case; ++j)
+               {
+                       double da2(a.ToDouble());
+                       s = RandomNumberAsString(max_digits);
+                       ParanoidNumber b(s);
+                       double db(b.ToDouble());
+       
+               
+       
+                       Optype op = Optype(rand() % 4);
+                       
+                       ParanoidNumber a_before(a);
+                       
+               
+                       switch (op)
+                       {
+                       case ADD:
+                               a += b;
+                               da += db;
+                               da2 += db;
+                               break;
+                       case SUBTRACT:
+                               a -= b;
+                               da -= db;
+                               da2 -= db;
+                               break;
+                       case MULTIPLY:
+                               a *= b;
+                               da *= db;
+                               da2 *= db;
+                               break;
+                       case DIVIDE:
+                               if (db == 0)
+                               {
+                                       --i;
+                               }
+                               else
+                               {
+                                       a /= b;
+                                       da /= db;
+                                       da2 /= db;
+                               }
+                               break;
+                       case NOP:
+                               break;
+                       }
+                       if (!CloseEnough(da2, a, eps))
+                       {
+                               Error("{%s} %c= {%s}", a_before.Str().c_str(), OpChar(op), b.Str().c_str());
+                               Error("{%s}", a.Str().c_str());
+                               Error("double Yields: %.40lf", da);
+                               Error("PN Yields: %.40lf", a.ToDouble());
+                               Fatal("Failed on case %i", i*ops_per_case + j-1);
+                       }
+               }
+               if (!CloseEnough(da, a, eps))
+               {
+                       Warn("double Yields: %.40lf", da);
+                       Warn("PN Yields: %.40lf", a.ToDouble());
+               }
+       }
+       Debug("Complete!");
+
 }
 
 #define TEST_CASES 1000
 
 int main(int argc, char ** argv)
 {
-       srand(time(NULL));
+       TestAddSubIntegers();
+       TestMulDivIntegers();
+       for (int i = 1; i <= 100; ++i)
+               TestRandomisedOps(1000, i);
+       return 0;
+       srand(0);//time(NULL)); //always test off same set
        string number(RandomNumberAsString());
        ParanoidNumber a(number);
+
        float fa = strtof(number.c_str(), NULL);
        double da = strtod(number.c_str(), NULL);
        double diff = 0;
        long double lda = strtold(number.c_str(), NULL);
-       
+       Debug("a is %s", a.Str().c_str());
        if (fabs(a.ToDouble() - da) > 1e-6)
        {
                Error("double %lf, pn %lf {%s}", da, a.ToDouble(), a.Str().c_str());
                Fatal("Didn't construct correctly off %s", number.c_str());
+               
        }
        
        char opch[] = {'+','-','*','/'};
@@ -109,14 +297,15 @@ int main(int argc, char ** argv)
                                break;
                }
                diff = 100.0*(fabs(a.ToDouble() - da) / da);
-               if (!CloseEnough(da, a))
+               if (!CloseEnough(lda, a))
                {
                        Error("Op %i: ParanoidNumber probably doesn't work", i);
                        Error("Operation: %lf %c %lf", oldda, opch[op], db);
                        Error("As PN: %lf %c %lf", olda.ToDouble(), opch[op], b.ToDouble());
+                       Error("PN String before: %s", olda.Str().c_str());
                        Error("PN String: %s", a.Str().c_str());
-                       Error("Diff is %.40lf", diff);
-                       Fatal("%.40lf, expected aboout %.40lf", a.ToDouble(), da);
+                       Error("LONG double gives %.40llf", lda);
+                       Fatal("%.40llf, expected aboout %.40llf", a.Convert<long double>(), lda);
                        
                        
                }

UCC git Repository :: git.ucc.asn.au