Project 2 - Fixed-Point Number Class
fixed.cpp
1 #include <cassert>
2 #include <cstdlib>
3 #include <iomanip>
4 #include <iostream>
5 #include <locale>
6 #include <sstream>
7 #include <stdexcept>
8 #include <string>
9 
10 #include "fixed.hpp"
11 #include "ioflags.hpp"
12 
13 // Construct a fixed value from an integer part and a fraction part
15 {
16  if (fraction < 0)
17  throw std::invalid_argument("negative fraction not allowed");
18  fraction = reduce(fraction);
19  if (integer < 0)
20  value_ = integer * places10 - fraction;
21  else
22  value_ = integer * places10 + fraction;
23 }
24 
25 // Construct a fixed value from an integer part with no fraction
27 : value_{integer * places10}
28 {}
29 
30 // Get the fraction part
32 const
33 {
34  return std::abs(value()) % places10;
35 }
36 
46 fixed::value_type fixed::reduce(value_type frac)
47 {
48  // First scan for zero digits on the right.
49  value_type f{frac};
50  while (f >= places10*10 and f % 10 == 0)
51  {
52  f /= 10;
53  }
54 
55  if (f >= places10*10)
56  {
57  int x{0};
58  // Loop ended because a non-zero digit was seen so Y* > 0.
59  // Discard the remaining digits, but keep track of the last
60  // digit to be processed (X).
61  while (f >= places10)
62  {
63  x = f % 10;
64  f /= 10;
65  }
66  // Round up if the last digit (X) is 5 or more
67  if (x >= 5)
68  ++f;
69  return f;
70  }
71  // Else all digits so far are zero. Check how many digits there were,
72  // that is, check whether G, and X at least are present.
73  else if (f >= places10)
74  {
75  // Yes, G and X are present. If X == 5, implement banker's rounding.
76  // Otherwise, round to nearest.
77  int x{f % 10};
78  f /= 10;
79  assert(f < places10);
80  if (x == 5)
81  {
82  // Yes, so implement banker's rounding.
83  if (f % 2 != 0)
84  ++f;
85  return f;
86  }
87  else if (x < 5)
88  {
89  // Round down.
90  return f;
91  }
92  else
93  {
94  // Round up.
95  return f + 1;
96  }
97  }
98  // Not enough digits, so nothing to round.
99  assert(frac < places10);
100  return frac;
101 }
102 
103 // Round off to nearest integer.
105 const
106 {
107  const value_type frac{fraction()};
108  int adjust{value() < 0 ? -1 : +1};
109  if (frac > places10/2)
110  return integer()+adjust;
111  else if (frac < places10/2)
112  return integer();
113  else if (integer() % 2 == 0)
114  return integer();
115  else
116  return integer()+adjust;
117 }
118 
119 // Convert to a string using fixed-point notation.
120 std::string fixed::as_string()
121 const
122 {
123  std::ostringstream out{};
124  out << integer() << '.'
125  << std::setfill('0') << std::setw(places) << fraction();
126  return out.str();
127 }
128 
130 {
131  value_ += f.value();
132  return *this;
133 }
134 
136 {
137  value_ -= f.value();
138  return *this;
139 }
140 
142 {
143  value_ = (value_ * f.value()) / places10;
144  return *this;
145 }
146 
148 {
149  value_ = (value_ * places10) / f.value();
150  return *this;
151 }
152 
154 {
155  value_ = -value_;
156 }
157 
159 {
160  value_ += places10;
161  return *this;
162 }
163 
165 {
166  fixed result{*this};
167  ++*this;
168  return result;
169 }
170 
172 {
173  value_ -= places10;
174  return *this;
175 }
176 
178 {
179  fixed result{*this};
180  --*this;
181  return result;
182 }
183 
185 {
186  a.negate();
187  return a;
188 }
189 
190 bool fixed::read(std::istream& strm)
191 {
192  ioflags flags(strm);
193 
195  char decimal{};
196  if (not (strm >> integer))
197  return false;
198  strm.unsetf(std::ios_base::skipws);
199  if (not (strm >> decimal) or decimal != '.')
200  {
201  // Just an integer is fine. Push back the non-decimal character,
202  // if there is one, and reset the stream flags to show that
203  // reading the fixed value succeeded.
204  strm.unget();
205  strm.clear(strm.rdstate() & ~strm.failbit);
206  value_ = integer * places10;
207  return true;
208  }
209  else
210  {
211  value_type fraction{0};
212  char c{};
213  int p{0};
214  // Read one extra place for round-off.
215  for (;
216  p != places+1 and strm >> c and std::isdigit(c, strm.getloc());
217  ++p)
218  {
219  fraction = fraction * 10 + (c - '0');
220  }
221  // Pad out to the requisite number of decimal places.
222  for (; p < places; ++p)
223  fraction = fraction * 10;
224  // If the loop terminated because the maximum number of decimal
225  // places were read, keep reading the stream to discard excees digits.
226  while (strm and std::isdigit(c, strm.getloc()))
227  strm >> c;
228  // Push back the last, non-digit character read from the stream.
229  // If the stream reached EOF, unget() is harmless.
230  strm.unget();
231  // Clear failbit because even if reading a character or whatever
232  // failed, reading the fixed value did not.
233  strm.clear(strm.rdstate() & ~strm.failbit);
234  fraction = reduce(fraction);
235  if (integer < 0)
236  value_ = integer * places10 - fraction;
237  else
238  value_ = integer * places10 + fraction;
239  }
240  return true;
241 }
242 
243 std::istream& operator>>(std::istream& strm, fixed& f)
244 {
245  if (not f.read(strm))
246  strm.setstate(strm.failbit);
247  return strm;
248 }
249 
250 std::ostream& operator<<(std::ostream& strm, fixed f)
251 {
252  strm << f.as_string();
253  return strm;
254 }
255 
257 {
258  a += b;
259  return a;
260 }
261 
263 {
264  a -= b;
265  return a;
266 }
267 
269 {
270  a *= b;
271  return a;
272 }
273 
275 {
276  a /= b;
277  return a;
278 }
279 
281 {
282  return a.value() == b.value();
283 }
284 
286 {
287  return not (a == b);
288 }
289 
291 {
292  return a.value() < b.value();
293 }
294 
296 {
297  return b < a;
298 }
299 
301 {
302  return not (b < a);
303 }
304 
306 {
307  return not (a < b);
308 }
fixed & operator*=(fixed f)
Multiplication assignment operator.
Definition: fixed.cpp:141
Implement a fixed-point number class. Values have places places after the decimal point...
Definition: fixed.hpp:37
fixed operator*(fixed a, fixed b)
Multiply fixed values.
Definition: fixed.cpp:268
std::string as_string() const
Definition: fixed.cpp:120
bool operator>=(fixed a, fixed b)
Compare fixed values for greater-than-or-equal by comparing the underlying values.
Definition: fixed.cpp:305
bool operator<=(fixed a, fixed b)
Compare fixed values for less-than-or-equal by comparing the underlying values.
Definition: fixed.cpp:300
bool operator<(fixed a, fixed b)
Compare fixed values for less-than by comparing the underlying values.
Definition: fixed.cpp:290
value_type value() const
Return the internal value.
Definition: fixed.hpp:107
value_type integer() const
Return the integer part (which is the same as trunc()).
Definition: fixed.hpp:81
Save and restore I/O stream flags.
std::ostream & operator<<(std::ostream &strm, fixed f)
Write a fixed value.
Definition: fixed.cpp:250
value_type fraction() const
Return the fractional part, e.g., 3 for 12.03.
Definition: fixed.cpp:31
bool operator!=(fixed a, fixed b)
Compare fixed values for inequality by comparing the underlying values.
Definition: fixed.cpp:285
static int const places
number of decimal places
Definition: fixed.hpp:42
bool operator>(fixed a, fixed b)
Compare fixed values for greater-than by comparing the underlying values.
Definition: fixed.cpp:295
fixed & operator++()
Pre-increment.
Definition: fixed.cpp:158
fixed & operator+=(fixed f)
Addition assignment operator.
Definition: fixed.cpp:129
fixed & operator/=(fixed f)
Division assignment operator.
Definition: fixed.cpp:147
fixed & operator--()
Pre-decrement.
Definition: fixed.cpp:171
fixed operator/(fixed a, fixed b)
Divide fixed values.
Definition: fixed.cpp:274
Fixed-point numbers.
void negate()
Negate this value.
Definition: fixed.cpp:153
fixed & operator-=(fixed f)
Subtraction assignment operator.
Definition: fixed.cpp:135
std::istream & operator>>(std::istream &strm, fixed &f)
Read a fixed value.
Definition: fixed.cpp:243
bool operator==(fixed a, fixed b)
Compare fixed values for equality by comparing the underlying values.
Definition: fixed.cpp:280
static value_type const places10
10places
Definition: fixed.hpp:43
fixed operator-(fixed a, fixed b)
Subtract fixed values.
Definition: fixed.cpp:262
int value_type
Type of the actual value.
Definition: fixed.hpp:40
fixed operator+(fixed a, fixed b)
Add fixed values.
Definition: fixed.cpp:256
value_type round() const
Definition: fixed.cpp:104
fixed()
Default constructor initializes to zero.
Definition: fixed.hpp:46
bool read(std::istream &strm)
Definition: fixed.cpp:190