-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterval_tests.cpp
193 lines (167 loc) · 5.63 KB
/
interval_tests.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#include <cassert>
#include <iostream>
#include "TimeInterval.h"
using namespace std;
// factor for increasing the count of denominators
static const int DENOM_FACTOR = 2;
/**
* \brief Reduce the provided numerator by succesive factors of the provided denominator.
*
* \return the amount the numerator was reduced by.
*/
long reduce_by_factor(long factor,
const TimeInterval &denominator,
TimeInterval &numerator)
{
TimeInterval total = denominator;
long quotient = 1;
long delta = 1;
int operations = 0;
if (factor <= 1) {
return 0;
}
// determine largest factor that denominator goes into numerator, and compute how many times
// the denominator goes into that.
// e.g. computing 15/3 using a factor of 2 would yield 4
// (try 2*3, then try 4*3, then try 8*3)
while (numerator >= total) {
delta *= factor;
total = denominator * delta;
operations += 2;
//cout << __LINE__ << " delta:" << delta << " total:" << total << endl;
}
delta /= factor;
total = denominator * delta;
operations += 2;
quotient = delta;
//cout << "delta:" << delta << " total:" << total << " numerator:" << numerator << endl;
// compute the number of times the the denominator goes into
// numerator - (largest factor * denominator)
// by successively lowering the multiplier
// e.g. computing 15/3, the largest factor found above is 4 and the total is 12
// so try 12 + (4*3), which won't work,
// then try 12 * (2*3) which won't work,
// then try 12 + (1*3) which wil fit
while (delta >= 1) {
while (numerator >= total) {
total += (denominator * delta);
quotient += delta;
operations += 2;
//cout << " delta:" << delta << " total:" << total << endl;
}
total -= (denominator * delta);
quotient -= delta;
delta /= factor;
operations += 3;
//cout << "delta:" << delta << " total:" << total << " numerator:" << numerator << endl;
}
//cout << "delta:" << delta << " total:" << total << " numerator:" << numerator << endl;
//cout << "operations:" << operations << endl;
numerator -= total;
return quotient;
}
/**
* \brief Divides one time interval by another
*
* Given two TimeInterval objects -- a numerator and a denominator -- computes
* the quotient (as a long integer) and the remainder (as another TimeInterval)
* when numerator is divided by denominator.
*
*/
void divide(const TimeInterval &numerator,
const TimeInterval &denominator,
long "ient,
TimeInterval &remainder)
{
quotient = 0;
remainder = numerator;
const TimeInterval zero(0, 0, 0);
if (denominator == zero) {
throw std::invalid_argument("Denominator cannot be zero");
}
if (denominator < zero) {
return; // should an exception get thrown here?
}
if (numerator < zero) {
return; // should an exception get thrown here?
}
#if 1
quotient = reduce_by_factor(DENOM_FACTOR, denominator, remainder);
#else
//
// The simplest algorithm...
//
while (remainder >= denominator) {
remainder -= denominator;
quotient++;
}
#endif
//
// Are there edge cases that aren't handled by the simple algorithm?
//
//
// Are there algorithms that can arrive at the answer much more efficiently?
//
}
int main(int argc, char **argv)
{
TimeInterval numerator;
TimeInterval denominator;
TimeInterval remainder;
const TimeInterval zero(0, 0, 0);
long quotient;
double seconds = 0.20;
//
// Add tests here to verify the correctness of your implementation
// of interval division
//
numerator.setInterval(500, 0, 0); // 500 days
denominator.setInterval(0, 0, 200000); // 0.2 seconds
long expectedQuotient = (500 * 24 * 60 * 60) / seconds;
// check for zero denominator
try {
divide(numerator, zero, quotient, remainder);
assert(false); // should not get here
} catch(exception &e) {
cout << "divide threw: " << e.what() << endl;
}
// check for numerator > denominator
divide(numerator, denominator, quotient, remainder);
cout << denominator << " divides " << numerator << " " << quotient << " times with a remainder of " << remainder << endl;
cout << "exp q:" << expectedQuotient << endl;
assert(quotient == expectedQuotient);
assert(remainder == zero);
// check for numerator < denominator
divide(denominator, numerator, quotient, remainder);
cout << numerator << " divides " << denominator << " " << quotient << " times with a remainder of " << remainder << endl;
assert(quotient == 0);
assert(remainder == denominator);
// check for numerator == denominator
divide(numerator, numerator, quotient, remainder);
cout << numerator << " divides " << numerator << " " << quotient << " times with a remainder of " << remainder << endl;
assert(quotient == 1);
assert(remainder == zero);
// some random tests
time_t now = time(NULL);
srandom(now);
for (int i = 0; i < 10; i++) {
int nDays = random() % 700;
int nSeconds = random() % (24 * 60 * 60);
int nUseconds = random() % 900000;
long daySeconds = (nDays * 24 * 60 * 60) + nSeconds;
TimeInterval days(nDays, nSeconds, 0);
TimeInterval uSeconds(0, 0, nUseconds);
long expectedQuotient = daySeconds / ( 0.000001 * nUseconds);
long expectedRemainInt = daySeconds * 1000000 - ((nUseconds ) * expectedQuotient) ;
TimeInterval expectedRemainder(0, 0, expectedRemainInt );
divide(days, uSeconds, quotient, remainder);
cout << uSeconds << " divides " << days << " " << quotient << " times, remainder:" << remainder << endl;
assert(quotient == expectedQuotient);
assert(expectedRemainder == remainder);
divide(uSeconds, days, quotient, remainder);
cout << days << " divides " << uSeconds << " " << quotient << " times, remainder:" << remainder << endl << endl;
assert(quotient == 0);
assert(remainder == uSeconds);
}
return 0;
}