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 long double pd = p.Convert<long double>();
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 (!CloseEnough(d, p))
69 Debug("%lf %c= %lf failed", p0, OpChar(op), amount);
70 Debug("%lf vs %lf", 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("Doubles Yield: %.40lf", d);
148 void TestRandomisedOps(int test_cases = 1000, int ops_per_case = 1, int max_digits = 4)
150 Debug("Test %i*%i randomised ops (max digits = %i)", test_cases, ops_per_case, max_digits);
151 long double eps = 1e-2; //* (1e4*ops_per_case);
152 for (int i = 0; i < test_cases; ++i)
154 string s = RandomNumberAsString(max_digits);
157 double da(a.ToDouble());
158 for (int j = 1; j <= ops_per_case; ++j)
160 double da2(a.ToDouble());
161 s = RandomNumberAsString(max_digits);
163 double db(b.ToDouble());
167 Optype op = Optype(rand() % 4);
169 ParanoidNumber a_before(a);
204 if (!CloseEnough(da2, a, eps))
206 Error("{%s} %c= {%s}", a_before.Str().c_str(), OpChar(op), b.Str().c_str());
207 Error("{%s}", a.Str().c_str());
208 Error("double Yields: %.40lf", da);
209 Error("PN Yields: %.40lf", a.ToDouble());
210 Fatal("Failed on case %i", i*ops_per_case + j-1);
213 if (!CloseEnough(da, a, eps))
215 Warn("double Yields: %.40lf", da);
216 Warn("PN Yields: %.40lf", a.ToDouble());
223 #define TEST_CASES 1000
225 int main(int argc, char ** argv)
227 TestAddSubIntegers();
228 TestMulDivIntegers();
229 for (int i = 1; i <= 100; ++i)
230 TestRandomisedOps(1000, i);
232 srand(0);//time(NULL)); //always test off same set
233 string number(RandomNumberAsString());
234 ParanoidNumber a(number);
236 float fa = strtof(number.c_str(), NULL);
237 double da = strtod(number.c_str(), NULL);
239 long double lda = strtold(number.c_str(), NULL);
240 Debug("a is %s", a.Str().c_str());
241 if (fabs(a.ToDouble() - da) > 1e-6)
243 Error("double %lf, pn %lf {%s}", da, a.ToDouble(), a.Str().c_str());
244 Fatal("Didn't construct correctly off %s", number.c_str());
248 char opch[] = {'+','-','*','/'};
249 int opcount[] = {0,0,0,0};
250 for (int i = 0; i < TEST_CASES; ++i)
252 ProgressBar(i, TEST_CASES); fprintf(stderr, "%.30lf (%d)+ (%d)- (%d)* (%d)/ [Paranoia %ld]",diff, opcount[0],opcount[1],opcount[2],opcount[3], ParanoidNumber::Paranoia());
253 number = RandomNumberAsString();
254 ParanoidNumber b(number);
255 float fb = strtof(number.c_str(), NULL);
256 double db = strtod(number.c_str(), NULL);
262 long double ldb = strtold(number.c_str(), NULL);
263 int op = rand() % 4;//= 2*(rand() % 2);
266 //if (rand() % 2 == 0)
267 //op = 2+(rand() % 2);
270 ParanoidNumber olda(a);
299 diff = 100.0*(fabs(a.ToDouble() - da) / da);
300 if (!CloseEnough(lda, a))
302 Error("Op %i: ParanoidNumber probably doesn't work", i);
303 Error("Operation: %lf %c %lf", oldda, opch[op], db);
304 Error("As PN: %lf %c %lf", olda.ToDouble(), opch[op], b.ToDouble());
305 Error("PN String before: %s", olda.Str().c_str());
306 Error("PN String: %s", a.Str().c_str());
307 Error("LONG double gives %.40llf", lda);
308 Fatal("%.40llf, expected aboout %.40llf", a.Convert<long double>(), lda);
314 printf("ParanoidNumber: {%s} = %.40lf\n", a.Str().c_str(), a.ToDouble());
315 printf("float: %.40f\n", fa);
316 printf("double: %.40lf\n", da);
317 printf("long double: %.40Lf\n", lda);
318 printf("diff %.40lf\n", diff);