10 #include "paranoidnumber.h"
11 #include "progressbar.h"
16 string RandomNumberAsString(int max_digits = 3)
19 int digits = 1+(rand() % max_digits);
20 int dp = (rand() % digits)+1;
21 for (int i = 0; i < digits; ++i)
28 result += ('0'+rand() % 10);
33 bool CloseEnough(long double d, ParanoidNumber & p, long double eps = 1e-6)
35 double pd = p.ToDouble();
38 return fabs(pd) <= eps;
39 return fabs((fabs(pd - d) / d)) <= eps;
42 void TestOp(ParanoidNumber & p, double & d, Optype op, const double amount)
44 string p0str(p.Str());
45 double p0 = p.ToDouble();
67 if (false)//(!CloseEnough(d, p))
69 Debug("%.40lf %c= %.40lf failed", p0, OpChar(op), amount);
70 Debug("%.40lf vs %.40lf", p.ToDouble(), d);
71 Debug("Before: {%s}\n", p0str.c_str());
72 Debug("After: {%s}\n", p.Str().c_str());
78 void TestAddSubIntegers(int max=100)
80 Debug("Test add/sub integers 0 -> %i", max);
83 for (int a = 0; a < max; ++a)
86 for (int b = 0; b < max; ++b)
88 TestOp(p, d, SUBTRACT, b);
90 for (int b = 0; b < max; ++b)
95 for (int a = 0; a < max; ++a)
97 TestOp(p, d, SUBTRACT, a);
98 for (int b = 0; b < max; ++b)
100 TestOp(p, d, ADD, b);
102 for (int b = 0; b < max; ++b)
104 TestOp(p, d, SUBTRACT, b);
107 Debug("PN Yields: %.40lf", p.ToDouble());
108 Debug("Doubles Yield: %.40lf", d);
113 void TestMulDivIntegers(int max=50)
115 Debug("Test mul/div integers 1 -> %i", max);
116 ParanoidNumber p(1.0);
118 for (int a = 1; a < max; ++a)
120 TestOp(p, d, MULTIPLY, a);
121 for (int b = 1; b < max; ++b)
123 TestOp(p, d, DIVIDE, b);
125 for (int b = 1; b < max; ++b)
127 TestOp(p, d, MULTIPLY, b);
130 for (int a = 1; a < max; ++a)
132 TestOp(p, d, DIVIDE, a);
133 for (int b = 1; b < max; ++b)
135 TestOp(p, d, MULTIPLY, b);
137 for (int b = 1; b < max; ++b)
139 TestOp(p, d, DIVIDE, b);
142 Debug("PN Yields: %.40lf", p.ToDouble());
143 Debug("PN is: %s", p.Str().c_str());
145 Debug("Doubles Yield: %.40lf", d);
150 void TestRandomisedOps(int test_cases = 1000, int ops_per_case = 1, int max_digits = 4)
152 Debug("Test %i*%i randomised ops (max digits = %i)", test_cases, ops_per_case, max_digits);
153 long double eps = 1; //* (1e4*ops_per_case);
154 for (int i = 0; i < test_cases; ++i)
156 string s = RandomNumberAsString(max_digits);
159 double da(a.ToDouble());
160 for (int j = 1; j <= ops_per_case; ++j)
162 double da2(a.ToDouble());
163 s = RandomNumberAsString(max_digits);
165 double db(b.ToDouble());
169 Optype op = Optype(rand() % 4);
171 ParanoidNumber a_before(a);
206 if (!CloseEnough(da2, a, eps))
208 Error("{%s} %c= {%s}", a_before.Str().c_str(), OpChar(op), b.Str().c_str());
209 Error("{%s}", a.Str().c_str());
210 Error("double Yields: %.40lf", da);
211 Error("PN Yields: %.40lf", a.ToDouble());
212 Fatal("Failed on case %i", i*ops_per_case + j-1);
215 if (!CloseEnough(da, a, eps))
217 Warn("double Yields: %.40lf", da);
218 Warn("PN Yields: %.40lf", a.ToDouble());
220 if (i == test_cases - 1)
222 Debug("double: %.40lf", da);
223 Debug("PN: %.40lf", a.ToDouble());
230 #define TEST_CASES 1000
232 int main(int argc, char ** argv)
234 TestAddSubIntegers(100);
235 TestMulDivIntegers(100);
236 for (int i = 1; i <= 100; ++i)
237 TestRandomisedOps(1000, i);
239 srand(0);//time(NULL)); //always test off same set
240 string number(RandomNumberAsString());
241 ParanoidNumber a(number);
243 float fa = strtof(number.c_str(), NULL);
244 double da = strtod(number.c_str(), NULL);
246 long double lda = strtold(number.c_str(), NULL);
247 Debug("a is %s", a.Str().c_str());
248 if (fabs(a.ToDouble() - da) > 1e-6)
250 Error("double %lf, pn %lf {%s}", da, a.ToDouble(), a.Str().c_str());
251 Fatal("Didn't construct correctly off %s", number.c_str());
255 char opch[] = {'+','-','*','/'};
256 int opcount[] = {0,0,0,0};
257 for (int i = 0; i < TEST_CASES; ++i)
259 ProgressBar(i, TEST_CASES); fprintf(stderr, "%.30lf (%d)+ (%d)- (%d)* (%d)/ [Paranoia %ld]",diff, opcount[0],opcount[1],opcount[2],opcount[3], ParanoidNumber::Paranoia());
260 number = RandomNumberAsString();
261 ParanoidNumber b(number);
262 float fb = strtof(number.c_str(), NULL);
263 double db = strtod(number.c_str(), NULL);
269 long double ldb = strtold(number.c_str(), NULL);
270 int op = rand() % 4;//= 2*(rand() % 2);
273 //if (rand() % 2 == 0)
274 //op = 2+(rand() % 2);
277 ParanoidNumber olda(a);
306 diff = 100.0*(fabs(a.ToDouble() - da) / da);
307 if (!CloseEnough(lda, a))
309 Error("Op %i: ParanoidNumber probably doesn't work", i);
310 Error("Operation: %lf %c %lf", oldda, opch[op], db);
311 Error("As PN: %lf %c %lf", olda.ToDouble(), opch[op], b.ToDouble());
312 Error("PN String before: %s", olda.Str().c_str());
313 Error("PN String: %s", a.Str().c_str());
314 Error("LONG double gives %.40llf", lda);
315 Error("%.40llf, expected aboout %.40llf", a.Convert<long double>(), lda);
321 printf("ParanoidNumber: {%s} = %.40lf\n", a.Str().c_str(), a.ToDouble());
322 printf("float: %.40f\n", fa);
323 printf("double: %.40lf\n", da);
324 printf("long double: %.40Lf\n", lda);
325 printf("diff %.40lf\n", diff);