Project 3 - Currency Type

- Main Page
- Classes
- Files

- File List
- File Members

fixed.hpp
Go to the documentation of this file.
1
4 #ifndef FIXED_HPP_
5 #define FIXED_HPP_
6
7 #include <cassert>
8 #include <cmath>
9 #include <iomanip>
10 #include <ios>
11 #include <istream>
12 #include <locale>
13 #include <ostream>
14 #include <sstream>
15 #include <stdexcept>
16 #include <string>
17
18 #include "ioflags.hpp"
19 #include "power10.hpp"
20
25 template<class T, int N>
26 class fixed
27 {
28 public:
29 typedef T value_type;
30
31 static value_type constexpr places{N};
32 static value_type constexpr places10{power10(N)};
33
35 constexpr fixed() : value_() {}
36
40 fixed(value_type integer, value_type fraction);
41
43 constexpr fixed(value_type integer);
44
46 fixed(double value)
47 : value_(static_cast<value_type>(value * places10 + (value < 0 ? -0.5 : 0.5)))
48 {}
49
52 std::string as_string() const;
57 template<class Char, class Traits>
58 bool read(std::basic_istream<Char, Traits>& strm);
60 double as_long_double() const { return static_cast<long double>(value()) / places10; }
62 double as_double() const { return static_cast<double>(value()) / places10; }
64 float as_float() const { return static_cast<float>(value()) / places10; }
68 value_type round() const;
69
71 value_type integer() const { return value() / places10; }
73 value_type fraction() const;
74
76 fixed& operator+=(fixed f);
78 fixed& operator-=(fixed f);
80 fixed& operator*=(fixed f);
82 fixed& operator/=(fixed f);
83
85 void negate();
86
88 fixed& operator++();
90 fixed operator++(int);
92 fixed& operator--();
94 fixed operator--(int);
95
97 value_type value() const { return value_; }
98 private:
100 value_type reduce(value_type frac);
101 value_type value_;
102 };
103
104 template<class T, int N>
105 typename fixed<T,N>::value_type constexpr fixed<T,N>::places10;
106
107 // Construct a fixed value from an integer part and a fraction part
108 template<class T, int N>
109 fixed<T,N>::fixed(value_type integer, value_type fraction)
110 {
111 if (fraction < T())
112 throw std::invalid_argument("negative fraction not allowed");
113 fraction = reduce(fraction);
114 if (integer < T())
115 value_ = integer * places10 - fraction;
116 else
117 value_ = integer * places10 + fraction;
118 }
119
120 // Construct a fixed value from an integer part with no fraction
121 template<class T, int N>
122 constexpr
123 fixed<T,N>::fixed(value_type integer)
124 : value_(integer * places10)
125 {}
126
127 // Get the fraction part
128 template<class T, int N>
129 typename fixed<T,N>::value_type fixed<T,N>::fraction()
130 const
131 {
132 return std::abs(value()) % places10;
133 }
134
144 template<class T, int N>
145 typename fixed<T,N>::value_type fixed<T,N>::reduce(value_type frac)
146 {
147 // First scan for zero digits on the right.
148 value_type f(frac);
149 while (f >= places10*10 and f % 10 == 0)
150 {
151 f /= 10;
152 }
153
154 if (f >= places10*10)
155 {
156 int x(0);
157 // Loop ended because a non-zero digit was seen so Y* > 0.
158 // Discard the remaining digits, but keep track of the last
159 // digit to be processed (X).
160 while (f >= places10)
161 {
162 x = f % 10;
163 f /= 10;
164 }
165 // Round up if the last digit (X) is 5 or more
166 if (x >= 5)
167 ++f;
168 return f;
169 }
170 // Else all digits so far are zero. Check how many digits there were,
171 // that is, check whether G, and X at least are present.
172 else if (f >= places10)
173 {
174 // Yes, G and X are present. If X == 5, implement banker's rounding.
175 // Otherwise, round to nearest.
176 int x(f % 10);
177 f /= 10;
178 assert(f < places10);
179 if (x == 5)
180 {
181 // Yes, so implement banker's rounding.
182 if (f % 2 != 0)
183 ++f;
184 return f;
185 }
186 else if (x < 5)
187 {
188 // Round down.
189 return f;
190 }
191 else
192 {
193 // Round up.
194 return f + 1;
195 }
196 }
197 // Not enough digits, so nothing to round.
198 assert(frac < places10);
199 return frac;
200 }
201
202 // Round off to nearest integer.
203 template<class T, int N>
204 typename fixed<T,N>::value_type fixed<T,N>::round()
205 const
206 {
207 const value_type frac(fraction());
208 int adjust(value() < 0 ? -1 : +1);
209 if (frac > places10/2)
210 return integer()+adjust;
211 else if (frac < places10/2)
212 return integer();
213 else if (integer() % 2 == 0)
214 return integer();
215 else
216 return integer()+adjust;
217 }
218
219 // Convert to a string using fixed-point notation.
220 template<class T, int N>
221 std::string fixed<T,N>::as_string()
222 const
223 {
224 std::ostringstream out;
225 out << integer() << '.'
226 << std::setfill('0') << std::setw(places) << fraction();
227 return out.str();
228 }
229
230 template<class T, int N>
231 fixed<T,N>& fixed<T,N>::operator+=(fixed f)
232 {
233 value_ += f.value();
234 return *this;
235 }
236
237 template<class T, int N>
238 fixed<T,N>& fixed<T,N>::operator-=(fixed f)
239 {
240 value_ -= f.value();
241 return *this;
242 }
243
244 template<class T, int N>
245 fixed<T,N>& fixed<T,N>::operator*=(fixed f)
246 {
247 value_ = (value_ * f.value()) / places10;
248 return *this;
249 }
250
251 template<class T, int N>
252 fixed<T,N>& fixed<T,N>::operator/=(fixed f)
253 {
254 value_ = (value_ * places10) / f.value();
255 return *this;
256 }
257
258 template<class T, int N>
259 void fixed<T,N>::negate()
260 {
261 value_ = -value_;
262 }
263
264 template<class T, int N>
265 fixed<T,N>& fixed<T,N>::operator++()
266 {
267 value_ += places10;
268 return *this;
269 }
270
271 template<class T, int N>
272 fixed<T,N> fixed<T,N>::operator++(int)
273 {
274 fixed result(*this);
275 ++*this;
276 return result;
277 }
278
279 template<class T, int N>
280 fixed<T,N>& fixed<T,N>::operator--()
281 {
282 value_ -= places10;
283 return *this;
284 }
285
286 template<class T, int N>
287 fixed<T,N> fixed<T,N>::operator--(int)
288 {
289 fixed result(*this);
290 --*this;
291 return result;
292 }
293
294 template<class T, int N>
295 template<class Char, class Traits>
296 bool fixed<T,N>::read(std::basic_istream<Char, Traits>& strm)
297 {
298 ioflags flags(strm);
299
300 value_type integer;
301 char decimal;
302 if (not (strm >> integer))
303 return false;
304 strm.unsetf(std::ios_base::skipws);
305 if (not (strm >> decimal) or decimal != '.')
306 {
307 // Just an integer is fine. Push back the non-decimal character,
308 // if there is one, and reset the stream flags to show that
309 // reading the fixed value succeeded.
310 strm.unget();
311 strm.clear(strm.rdstate() & ~strm.failbit);
312 value_ = integer * places10;
313 return true;
314 }
315 else
316 {
317 value_type fraction(0);
318 char c;
319 int p(0);
320 // Read one extra place for round-off.
321 for (;
322 p != places+1 and strm >> c and std::isdigit(c, strm.getloc());
323 ++p)
324 {
325 fraction = fraction * 10 + (c - '0');
326 }
327 // Pad out to the requisite number of decimal places.
328 for (; p < places; ++p)
329 fraction = fraction * 10;
330 // If the loop terminated because the maximum number of decimal
331 // places were read, keep reading the stream to discard excees digits.
332 while (strm and std::isdigit(c, strm.getloc()))
333 strm >> c;
334 // Push back the last, non-digit character read from the stream.
335 // If the stream reached EOF, unget() is harmless.
336 strm.unget();
337 // Clear failbit because even if reading a character or whatever
338 // failed, reading the fixed value did not.
339 strm.clear(strm.rdstate() & ~strm.failbit);
340 fraction = reduce(fraction);
341 if (integer < 0)
342 value_ = integer * places10 - fraction;
343 else
344 value_ = integer * places10 + fraction;
345 }
346 return true;
347 }
348
350 template<class T, int N, class Char, class Traits>
351 std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& strm, fixed<T,N>& f)
352 {
353 if (not f.read(strm))
354 strm.setstate(strm.failbit);
355 return strm;
356 }
357
359 template<class T, int N, class Char, class Traits>
360 std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& strm, fixed<T,N> f)
361 {
362 strm << f.as_string();
363 return strm;
364 }
365
367 template<class T, int N>
368 fixed<T,N> operator+(fixed<T,N> a, fixed<T,N> b)
369 {
370 a += b;
371 return a;
372 }
373
375 template<class T, int N>
376 fixed<T,N> operator-(fixed<T,N> a, fixed<T,N> b)
377 {
378 a -= b;
379 return a;
380 }
381
383 template<class T, int N>
384 fixed<T,N> operator*(fixed<T,N> a, fixed<T,N> b)
385 {
386 a *= b;
387 return a;
388 }
389
391 template<class T, int N>
392 fixed<T,N> operator/(fixed<T,N> a, fixed<T,N> b)
393 {
394 a /= b;
395 return a;
396 }
397
399 template<class T, int N>
400 fixed<T,N> operator-(fixed<T,N> a)
401 {
402 a.negate();
403 return a;
404 }
405
407 template<class T, int N>
408 bool operator==(fixed<T,N> a, fixed<T,N> b)
409 {
410 return a.value() == b.value();
411 }
413 template<class T, int N>
414 bool operator==(T a, fixed<T,N> b)
415 {
416 return a == b.value();
417 }
419 template<class T, int N>
420 bool operator==(fixed<T,N> a, T b)
421 {
422 return a.value() == b;
423 }
424
426 template<class T, int N>
427 bool operator!=(fixed<T,N> a, fixed<T,N> b)
428 {
429 return not (a == b);
430 }
432 template<class T, int N>
433 bool operator!=(T a, fixed<T,N> b)
434 {
435 return not (a == b);
436 }
438 template<class T, int N>
439 bool operator!=(fixed<T,N> a, T b)
440 {
441 return not (a == b);
442 }
443
445 template<class T, int N>
446 bool operator<(fixed<T,N> a, fixed<T,N> b)
447 {
448 return a.value() < b.value();
449 }
451 template<class T, int N>
452 bool operator<(T a, fixed<T,N> b)
453 {
454 return a < b.value();
455 }
457 template<class T, int N>
458 bool operator<(fixed<T,N> a, T b)
459 {
460 return a.value() < b;
461 }
462
464 template<class T, int N>
465 bool operator>(fixed<T,N> a, fixed<T,N> b)
466 {
467 return b < a;
468 }
470 template<class T, int N>
471 bool operator>(T a, fixed<T,N> b)
472 {
473 return b < a;
474 }
476 template<class T, int N>
477 bool operator>(fixed<T,N> a, T b)
478 {
479 return b < a;
480 }
481
483 template<class T, int N>
484 bool operator<=(fixed<T,N> a, fixed<T,N> b)
485 {
486 return not (b < a);
487 }
489 template<class T, int N>
490 bool operator<=(T a, fixed<T,N> b)
491 {
492 return not (b < a);
493 }
495 template<class T, int N>
496 bool operator<=(fixed<T,N> a, T b)
497 {
498 return not (b < a);
499 }
500
502 template<class T, int N>
503 bool operator>=(fixed<T,N> a, fixed<T,N> b)
504 {
505 return not (a < b);
506 }
508 template<class T, int N>
509 bool operator>=(T a, fixed<T,N> b)
510 {
511 return not (a < b);
512 }
514 template<class T, int N>
515 bool operator>=(fixed<T,N> a, T b)
516 {
517 return not (a < b);
518 }
519
520 #endif
fixed::as_long_double
double as_long_double() const
Convert to long double.
Definition: fixed.hpp:60
operator+
currency< T, N > operator+(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:304
fixed
Implement a fixed-point number class template. Values have N places after the decimal point...
Definition: fixed.hpp:26
operator==
bool operator==(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:366
operator*
currency< T, N > operator*(currency< T, N > a, T b)
Definition: currency.hpp:324
fixed::as_string
std::string as_string() const
Definition: fixed.hpp:221
fixed::operator++
fixed & operator++()
Pre-increment.
Definition: fixed.hpp:265
operator/
currency< T, N > operator/(currency< T, N > a, T b)
Definition: currency.hpp:344
fixed::as_float
float as_float() const
Convert to float.
Definition: fixed.hpp:64
fixed::fixed
constexpr fixed()
Default constructor initializes to zero.
Definition: fixed.hpp:35
ioflags.hpp
Save and restore I/O stream flags.
fixed::value_type
T value_type
Type of the actual value.
Definition: fixed.hpp:29
fixed::operator--
fixed & operator--()
Pre-decrement.
Definition: fixed.hpp:280
fixed::places10
static value_type constexpr places10
10places
Definition: fixed.hpp:32
operator!=
bool operator!=(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:391
fixed::as_double
double as_double() const
Convert to double.
Definition: fixed.hpp:62
fixed::fraction
value_type fraction() const
Return the fractional part, e.g., 3 for 12.03.
Definition: fixed.hpp:129
fixed::round
value_type round() const
Definition: fixed.hpp:204
fixed::operator*=
fixed & operator*=(fixed f)
Multiplication assignment operator.
Definition: fixed.hpp:245
fixed::fixed
fixed(double value)
Construct by rounding off a floating point number.
Definition: fixed.hpp:46
operator>=
bool operator>=(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:491
fixed::operator-=
fixed & operator-=(fixed f)
Subtraction assignment operator.
Definition: fixed.hpp:238
ioflags
Definition: ioflags.hpp:15
fixed::operator/=
fixed & operator/=(fixed f)
Division assignment operator.
Definition: fixed.hpp:252
fixed::integer
value_type integer() const
Return the integer part (which is the same as trunc()).
Definition: fixed.hpp:71
fixed::read
bool read(std::basic_istream< Char, Traits > &strm)
Definition: fixed.hpp:296
fixed::value
value_type value() const
Return the internal value.
Definition: fixed.hpp:97
operator>
bool operator>(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:441
fixed::negate
void negate()
Negate this value.
Definition: fixed.hpp:259
operator>>
std::basic_istream< Char, Traits > & operator>>(std::basic_istream< Char, Traits > &strm, currency< T, N > &c)
Definition: currency.hpp:274
fixed::places
static value_type constexpr places
number of decimal places
Definition: fixed.hpp:31
fixed::operator+=
fixed & operator+=(fixed f)
Addition assignment operator.
Definition: fixed.hpp:231
operator-
currency< T, N > operator-(currency< T, N > a)
Negate a currency value.
Definition: currency.hpp:294