Project 2 - Fixed-Point Number Class

- Main Page
- Classes
- Files

- File List
- File Members

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
14 fixed::fixed(value_type integer, value_type fraction)
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
26 fixed::fixed(value_type integer)
27 : value_{integer * places10}
28 {}
29
30 // Get the fraction part
31 fixed::value_type fixed::fraction()
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.
104 fixed::value_type fixed::round()
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
129 fixed& fixed::operator+=(fixed f)
130 {
131 value_ += f.value();
132 return *this;
133 }
134
135 fixed& fixed::operator-=(fixed f)
136 {
137 value_ -= f.value();
138 return *this;
139 }
140
141 fixed& fixed::operator*=(fixed f)
142 {
143 value_ = (value_ * f.value()) / places10;
144 return *this;
145 }
146
147 fixed& fixed::operator/=(fixed f)
148 {
149 value_ = (value_ * places10) / f.value();
150 return *this;
151 }
152
153 void fixed::negate()
154 {
155 value_ = -value_;
156 }
157
158 fixed& fixed::operator++()
159 {
160 value_ += places10;
161 return *this;
162 }
163
164 fixed fixed::operator++(int)
165 {
166 fixed result{*this};
167 ++*this;
168 return result;
169 }
170
171 fixed& fixed::operator--()
172 {
173 value_ -= places10;
174 return *this;
175 }
176
177 fixed fixed::operator--(int)
178 {
179 fixed result{*this};
180 --*this;
181 return result;
182 }
183
184 fixed operator-(fixed a)
185 {
186 a.negate();
187 return a;
188 }
189
190 bool fixed::read(std::istream& strm)
191 {
192 ioflags flags(strm);
193
194 value_type integer{};
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
256 fixed operator+(fixed a, fixed b)
257 {
258 a += b;
259 return a;
260 }
261
262 fixed operator-(fixed a, fixed b)
263 {
264 a -= b;
265 return a;
266 }
267
268 fixed operator*(fixed a, fixed b)
269 {
270 a *= b;
271 return a;
272 }
273
274 fixed operator/(fixed a, fixed b)
275 {
276 a /= b;
277 return a;
278 }
279
280 bool operator==(fixed a, fixed b)
281 {
282 return a.value() == b.value();
283 }
284
285 bool operator!=(fixed a, fixed b)
286 {
287 return not (a == b);
288 }
289
290 bool operator<(fixed a, fixed b)
291 {
292 return a.value() < b.value();
293 }
294
295 bool operator>(fixed a, fixed b)
296 {
297 return b < a;
298 }
299
300 bool operator<=(fixed a, fixed b)
301 {
302 return not (b < a);
303 }
304
305 bool operator>=(fixed a, fixed b)
306 {
307 return not (a < b);
308 }
fixed::operator*=
fixed & operator*=(fixed f)
Multiplication assignment operator.
Definition: fixed.cpp:141
fixed
Implement a fixed-point number class. Values have places places after the decimal point...
Definition: fixed.hpp:37
operator*
fixed operator*(fixed a, fixed b)
Multiply fixed values.
Definition: fixed.cpp:268
fixed::as_string
std::string as_string() const
Definition: fixed.cpp:120
operator>=
bool operator>=(fixed a, fixed b)
Compare fixed values for greater-than-or-equal by comparing the underlying values.
Definition: fixed.cpp:305
operator<=
bool operator<=(fixed a, fixed b)
Compare fixed values for less-than-or-equal by comparing the underlying values.
Definition: fixed.cpp:300
operator<
bool operator<(fixed a, fixed b)
Compare fixed values for less-than by comparing the underlying values.
Definition: fixed.cpp:290
fixed::value
value_type value() const
Return the internal value.
Definition: fixed.hpp:107
fixed::integer
value_type integer() const
Return the integer part (which is the same as trunc()).
Definition: fixed.hpp:81
ioflags.hpp
Save and restore I/O stream flags.
operator<<
std::ostream & operator<<(std::ostream &strm, fixed f)
Write a fixed value.
Definition: fixed.cpp:250
fixed::fraction
value_type fraction() const
Return the fractional part, e.g., 3 for 12.03.
Definition: fixed.cpp:31
operator!=
bool operator!=(fixed a, fixed b)
Compare fixed values for inequality by comparing the underlying values.
Definition: fixed.cpp:285
fixed::places
static int const places
number of decimal places
Definition: fixed.hpp:42
operator>
bool operator>(fixed a, fixed b)
Compare fixed values for greater-than by comparing the underlying values.
Definition: fixed.cpp:295
fixed::operator++
fixed & operator++()
Pre-increment.
Definition: fixed.cpp:158
fixed::operator+=
fixed & operator+=(fixed f)
Addition assignment operator.
Definition: fixed.cpp:129
fixed::operator/=
fixed & operator/=(fixed f)
Division assignment operator.
Definition: fixed.cpp:147
fixed::operator--
fixed & operator--()
Pre-decrement.
Definition: fixed.cpp:171
operator/
fixed operator/(fixed a, fixed b)
Divide fixed values.
Definition: fixed.cpp:274
fixed.hpp
Fixed-point numbers.
ioflags
Definition: ioflags.hpp:15
fixed::negate
void negate()
Negate this value.
Definition: fixed.cpp:153
fixed::operator-=
fixed & operator-=(fixed f)
Subtraction assignment operator.
Definition: fixed.cpp:135
operator>>
std::istream & operator>>(std::istream &strm, fixed &f)
Read a fixed value.
Definition: fixed.cpp:243
operator==
bool operator==(fixed a, fixed b)
Compare fixed values for equality by comparing the underlying values.
Definition: fixed.cpp:280
fixed::places10
static value_type const places10
10places
Definition: fixed.hpp:43
operator-
fixed operator-(fixed a, fixed b)
Subtract fixed values.
Definition: fixed.cpp:262
fixed::value_type
int value_type
Type of the actual value.
Definition: fixed.hpp:40
operator+
fixed operator+(fixed a, fixed b)
Add fixed values.
Definition: fixed.cpp:256
fixed::round
value_type round() const
Definition: fixed.cpp:104
fixed::fixed
fixed()
Default constructor initializes to zero.
Definition: fixed.hpp:46
fixed::read
bool read(std::istream &strm)
Definition: fixed.cpp:190