1 | ////////////////////////////////////////////////////////////////////////////////
|
2 | //
|
3 | // Time-stamp: "09.07.09 18:20 fixpoint.h klaus?wachtler.de"
|
4 | //
|
5 | ////////////////////////////////////////////////////////////////////////////////
|
6 | //
|
7 | //
|
8 | // C++ templates defining numerical fixed point types
|
9 | // --------------------------------------------------
|
10 | //
|
11 | //
|
12 | // The functions are intended to be light weight and useful on small
|
13 | // systems like micro controllers.
|
14 | //
|
15 | // Speed and code size might be a little worse than integral
|
16 | // calculations but much better than floating point arithmetic
|
17 | // especially on systems without FPU.
|
18 | //
|
19 | // Tested with g++ 4.3.2 and avr-gcc 4.3.2.
|
20 | //
|
21 | // ATTENTION!
|
22 | // The code is tested only partially (as from 09.07.2009).
|
23 | // Not usable for production code.
|
24 | //
|
25 | ////////////////////////////////////////////////////////////////////////////////
|
26 | //
|
27 | // (C) 2009 Klaus Wachtler
|
28 | // Breidingstr. 17
|
29 | // D-29614 Soltau
|
30 | // Phone: +49-171-4553039
|
31 | // Mail: fixpoint<you guess the character?>wachtler.de
|
32 | //
|
33 | // This program is free software; you can redistribute it and/or
|
34 | // modify it under the terms of the GNU General Public License as
|
35 | // published by the Free Software Foundation; either version 3 of the
|
36 | // License, or (at your option) any later version.
|
37 | //
|
38 | // This program is distributed in the hope that it will be useful, but
|
39 | // WITHOUT ANY WARRANTY; without even the implied warranty of
|
40 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
41 | // General Public License for more details.
|
42 | // You should have received a copy of the GNU General Public License
|
43 | // along with this program; if not, see <http://www.gnu.org/licenses/>.
|
44 | //
|
45 | ////////////////////////////////////////////////////////////////////////////////
|
46 | //
|
47 | // Template arguments:
|
48 | //////////////////////
|
49 | //
|
50 | // - TBASE is some usual signed or unsigned integral type like
|
51 | // signed/unsigned int, int32_t, uint32_t etc..
|
52 | // TBASE is used to keep an internal value which has to be scaled to
|
53 | // get the correct number.
|
54 | //
|
55 | // - TTEMP is another integral type used for values subject to
|
56 | // overflow if TBASE would be used.
|
57 | // You might want to use the same type for TBASE and TTEMP (like
|
58 | // fixpoint< int16_t, int16_t >) as long as you ensure to keep
|
59 | // intermediate results like in a*b within valid range.
|
60 | // If in doubt choose TTEMP one step larger than TBASE, so
|
61 | // fixpoint< uint8_t, uint16_t > or fixpoint< int32_t, int64_t >
|
62 | // seem to be a good choice.
|
63 | // Default ist TBASE.
|
64 | //
|
65 | // - LFRACTIONAL scales this value and determines range and
|
66 | // accuracy. It counts in binary digits.
|
67 | // A positive value of LFRACTIONAL gives a type with reduced range
|
68 | // and accuracy better than 1 by using LFRACTIONAL binary digits as
|
69 | // fractional part (LFRACTIONAL digits are used for the fractional
|
70 | // part, the rest of TBASE is used for the integer part),
|
71 | // while negative values of LFRACTIONAL give an extended range with
|
72 | // less accuracy (compared to TBASE).
|
73 | // * Example 1:
|
74 | // fixpoint< uint16_t, 3 > is based on uint16_t scaled
|
75 | // by 2**3=8.
|
76 | // While uint16_t has a range from 0 to 65535 with steps of 1
|
77 | // fixpoint< uint16_t, 3 > has values from 0 to 8191.875 (65535/8)
|
78 | // with steps of 1/8=0.125. The fractional part is 3 binary
|
79 | // digits.
|
80 | // Possible values are 0, 0.125, 0.25, 0.375, 0.5 ... 8191.875.
|
81 | // * Example 2:
|
82 | // fixpoint< uint8_t, -2 > is based on uint8_t scaled
|
83 | // by 2**(-2)=1/4.
|
84 | // The values range from 0 (0*4) to 1020 (255*4) in steps of 4.
|
85 | // Possible values are 0, 4, 8, 12, ... 1020.
|
86 | // * Example 3:
|
87 | // fixpoint< uint8_t, 0 > is based on uint8_t without scaling.
|
88 | // This resembles uint8_t with values from 0 to 255.
|
89 | // * Example 4:
|
90 | // fixpoint< int8_t, -2 > is based on int8_t scaled
|
91 | // by 2**(-2)=1/4.
|
92 | // The values range from -512 (-128*4) to +508 (127*4) in steps of 4.
|
93 | // Possible values are -512, -508, -502, ... -4, 0, +4, ... +508.
|
94 | //
|
95 | // - ROUNDTONEAREST determines if assignments and initializations
|
96 | // cut off trailing digits (false) or rounds up to the nearest
|
97 | // integral value (true).
|
98 | // Default is true.
|
99 | //
|
100 | ////////////////////////////////////////////////////////////////////////////////
|
101 | //
|
102 | // Usage:
|
103 | /////////
|
104 | //
|
105 | // Compilation:
|
106 | //
|
107 | // - Plain C is not supported. Use C++.
|
108 | // - Use #include <fixpoint.h> and give -I... if necessary.
|
109 | // - No libs needed (everything is inlined).
|
110 | // - Compile with -DNO_STDSTRING or #define NO_STDSTRING before
|
111 | // #include <fixpoint.h> if no std::string is available.
|
112 | // - Compile with -DNO_STDIOSTREAM or #define NO_STDIOSTREAM before
|
113 | // #include <fixpoint.h> if no iostreams are available.
|
114 | // - Don't worry about warnings saying "shift count is negative".
|
115 | // This occurs in dead code which will be optimized away by the
|
116 | // compiler later.
|
117 | //
|
118 | //
|
119 | // Object creation:
|
120 | //
|
121 | // fixpoint objects can be created either:
|
122 | // - without arguments (resulting in a 0 value)
|
123 | // - an integral value (with their base type); values being not
|
124 | // integral can not be defined this way even if LFRACTIONAL is
|
125 | // positive
|
126 | // - two integral values a and b (resulting in a/b, which will be cut
|
127 | // off or rounded to a valid value depending on template argument
|
128 | // ROUNDTONEAREST); this is done by a template method with any
|
129 | // integral types for a and b and usual C style promotions
|
130 | // performing the division.
|
131 | // If LFRACTIONAL is positive the type TTEMP should be wide enough to
|
132 | // hold a<<LFRACTIONAL. If LFRACTIONAL is negative TTEMP should be
|
133 | // able to keep b<<LFRACTIONAL.
|
134 | // - a floating point number (which will be cut off or rounded
|
135 | // to a valid value depending on template argument ROUNDTONEAREST)
|
136 | //
|
137 | //
|
138 | // Valid operations:
|
139 | //
|
140 | // | type of a | type of b | result | lvalue | notes
|
141 | // -----------+-----------+-----------+----------+--------+------------------------------
|
142 | // f() | | | fixpoint | | constructor
|
143 | // -----------+-----------+-----------+----------+--------+------------------------------
|
144 | // f(a) | base type | | fixpoint | | constructor (1)
|
145 | // -----------+-----------+-----------+----------+--------+------------------------------
|
146 | // f(a) | double | | fixpoint | | constructor
|
147 | // -----------+-----------+-----------+----------+--------+------------------------------
|
148 | // f(a,b) | integral | integral | fixpoint | | constructor (1)
|
149 | // -----------+-----------+-----------+----------+--------+------------------------------
|
150 | // !a | fixpoint | | bool | | true if a==0
|
151 | // -----------+-----------+-----------+----------+--------+------------------------------
|
152 | // ++a | fixpoint | | fixpoint | yes | nop if LFRACTIONAL<0
|
153 | // -----------+-----------+-----------+----------+--------+------------------------------
|
154 | // a++ | fixpoint | | fixpoint | | nop if LFRACTIONAL<0
|
155 | // -----------+-----------+-----------+----------+--------+------------------------------
|
156 | // --a | fixpoint | | fixpoint | yes | nop if LFRACTIONAL<0
|
157 | // -----------+-----------+-----------+----------+--------+------------------------------
|
158 | // a-- | fixpoint | | fixpoint | | nop if LFRACTIONAL<0
|
159 | // -----------+-----------+-----------+----------+--------+------------------------------
|
160 | // +a | fixpoint | | fixpoint | | nop
|
161 | // -----------+-----------+-----------+----------+--------+------------------------------
|
162 | // -a | fixpoint | | fixpoint | |
|
163 | // -----------+-----------+-----------+----------+--------+------------------------------
|
164 | // a*b | fixpoint | fixpoint | fixpoint | | (1)
|
165 | // -----------+-----------+-----------+----------+--------+------------------------------
|
166 | // a/b | fixpoint | fixpoint | fixpoint | |
|
167 | // -----------+-----------+-----------+----------+--------+------------------------------
|
168 | // a%b | fixpoint | fixpoint | fixpoint | | x-n*y with n=x/y rounded -> 0
|
169 | // -----------+-----------+-----------+----------+--------+------------------------------
|
170 | // a+b | fixpoint | fixpoint | fixpoint | |
|
171 | // -----------+-----------+-----------+----------+--------+------------------------------
|
172 | // a-b | fixpoint | fixpoint | fixpoint | |
|
173 | // -----------+-----------+-----------+----------+--------+------------------------------
|
174 | // a<b | fixpoint | fixpoint | bool | |
|
175 | // -----------+-----------+-----------+----------+--------+------------------------------
|
176 | // a>b | fixpoint | fixpoint | bool | |
|
177 | // -----------+-----------+-----------+----------+--------+------------------------------
|
178 | // a<=b | fixpoint | fixpoint | bool | |
|
179 | // -----------+-----------+-----------+----------+--------+------------------------------
|
180 | // a>=b | fixpoint | fixpoint | bool | |
|
181 | // -----------+-----------+-----------+----------+--------+------------------------------
|
182 | // == | fixpoint | fixpoint | bool | |
|
183 | // -----------+-----------+-----------+----------+--------+------------------------------
|
184 | // != | fixpoint | fixpoint | bool | |
|
185 | // -----------+-----------+-----------+----------+--------+------------------------------
|
186 | // a&&b | fixpoint | fixpoint | bool | |
|
187 | // -----------+-----------+-----------+----------+--------+------------------------------
|
188 | // a||b | fixpoint | fixpoint | bool | |
|
189 | // -----------+-----------+-----------+----------+--------+------------------------------
|
190 | // a=b | fixpoint | any (2) | fixpoint | |
|
191 | // -----------+-----------+-----------+----------+--------+------------------------------
|
192 | // a+=b | fixpoint | any (2) | fixpoint | |
|
193 | // -----------+-----------+-----------+----------+--------+------------------------------
|
194 | // a-=b | fixpoint | any (2) | fixpoint | |
|
195 | // -----------+-----------+-----------+----------+--------+------------------------------
|
196 | // a*=b | fixpoint | any (2) | fixpoint | | (1)
|
197 | // -----------+-----------+-----------+----------+--------+------------------------------
|
198 | // a/=b | fixpoint | any (2) | fixpoint | |
|
199 | // -----------+-----------+-----------+----------+--------+------------------------------
|
200 | // a%=b | fixpoint | any (2) | fixpoint | |
|
201 | // -----------+-----------+-----------+----------+--------+------------------------------
|
202 | // (double) | fixpoint | | double | |
|
203 | // -----------+-----------+-----------+----------+--------+------------------------------
|
204 | // (int8_t) | fixpoint | | int8_t | | (1)
|
205 | // -----------+-----------+-----------+----------+--------+------------------------------
|
206 | // (int16_t) | fixpoint | | int16_t | | (1)
|
207 | // -----------+-----------+-----------+----------+--------+------------------------------
|
208 | // (int32_t) | fixpoint | | int32_t | | (1)
|
209 | // -----------+-----------+-----------+----------+--------+------------------------------
|
210 | // (int64_t) | fixpoint | | int64_t | | (1)
|
211 | // -----------+-----------+-----------+----------+--------+------------------------------
|
212 | // (uint8_t) | fixpoint | | uint8_t | | (1)
|
213 | // -----------+-----------+-----------+----------+--------+------------------------------
|
214 | // (uint16_t) | fixpoint | | uint16_t | | (1)
|
215 | // -----------+-----------+-----------+----------+--------+------------------------------
|
216 | // (uint32_t) | fixpoint | | uint32_t | | (1)
|
217 | // -----------+-----------+-----------+----------+--------+------------------------------
|
218 | // (uint64_t) | fixpoint | | uint64_t | | (1)
|
219 | // -----------+-----------+-----------+----------+--------+------------------------------
|
220 | //
|
221 | // (1) In operations like a*b an intermediate result might overflow
|
222 | // if TTEMP is as narrow as TBASE.
|
223 | // Please take care of the values and ranges. If in doubt choose
|
224 | // TTEMP wider than TBASE.
|
225 | //
|
226 | // (2) "any" means any type which can be converted to fixpoint,
|
227 | // i.e. the same fixpoint type, any integral type, float and double.
|
228 | //
|
229 | //
|
230 | // There is no implicit conversion between different fixpoint types.
|
231 | // Please convert manually. Example:
|
232 | // Anyware::fixpoint< int16_t, int32_t, 2 > a( 4 );
|
233 | // Anyware::fixpoint< int32_t, int32_t, 8 > b( a.getBaseValue(),
|
234 | // 1<<a.getScaleBinaryExponent()
|
235 | // );
|
236 | //
|
237 | //
|
238 | ////////////////////////////////////////////////////////////////////////////////
|
239 | //
|
240 | // History:
|
241 | ///////////
|
242 | //
|
243 | // 08.07.2009 kw - created
|
244 | // - tested on Linux + g++ 4.3.2 and avr-g++ 4.3.2
|
245 | //
|
246 | // 09.07.2009 kw - template argument TTEMP
|
247 | // - types for intermediate values changed
|
248 | // - more comments
|
249 | // - test programs
|
250 | //
|
251 | // kw
|
252 | //
|
253 | // kw
|
254 | //
|
255 | // kw
|
256 | //
|
257 | // kw
|
258 | //
|
259 | ////////////////////////////////////////////////////////////////////////////////
|
260 | //
|
261 | // TODO:
|
262 | ////////
|
263 | //
|
264 | // - testing all cases (with rounding and without)
|
265 | // - external documentation
|
266 | // - take care for ROUNDTONEAREST in operator ...int...
|
267 | // -
|
268 | // -
|
269 | // -
|
270 | // -
|
271 | // -
|
272 | //
|
273 | ////////////////////////////////////////////////////////////////////////////////
|
274 | //
|
275 | // There are 2 demo programs:
|
276 | //
|
277 | // - testfixpoint_linux.cpp shows basic usage and makes some tests,
|
278 | // written for a PC system running Linux. It might or might not work on
|
279 | // other systems; there is no GUI needed.
|
280 | //
|
281 | // - AVR_LCD44780_fixpoint.cpp, lcd-routines.c and lcd-routines.h are
|
282 | // used to build a test program running on an Atmel AVR (AtMega8
|
283 | // tested).
|
284 | //
|
285 | // It calculates some things in a loop until 10 seconds are elapsed
|
286 | // and writes the loop count to an LCD (Hitachi HDC44780).
|
287 | // For more information on connecting the AVR and the LCD see
|
288 | // AVR_LCD44780_fixpoint.cpp.
|
289 | // Changes on pin usage may be done in lcd-routines.h.
|
290 | //
|
291 | // Inside AVR_LCD44780_fixpoint.cpp there is a typedef where you can
|
292 | // set the type used for all calculations.
|
293 | // As long as you use C types here (int16_t, uint32_t, float etc.;
|
294 | // no fixpoint) the source file may be renamed to
|
295 | // AVR_LCD44780_fixpoint.c and compiled as traditional C for
|
296 | // comparison.
|
297 | //
|
298 | // There are two makefiles supplied: Makefile_AVR_c and Makefile_AVR_cpp
|
299 | // can be used to compile and flash the program on my system (atmega8,
|
300 | // 16 MHz, siprog using /dev/ttyS0) the C resp. C++ version or
|
301 | // modified as needed.
|
302 | // The Makefiles are derived from the sample files at [2].
|
303 | // Caution! The original Makefile from [2] will overwrite the
|
304 | // C++ source (*.cpp) with the listing, because the replacement in the line:
|
305 | // CPPFLAGS += -Wa,-adhlns=$(<:.c=.lst)
|
306 | // fails (since the extension is not .c).
|
307 | // This leads to a listing file name identical to the source file
|
308 | // name.
|
309 | // I changed the listing file name to the full source name and .lst
|
310 | // appended, e.g. AVR_LCD44780_fixpoint.cpp.lst to avoid the mess.
|
311 | //
|
312 | ////////////////////////////////////////////////////////////////////////////////
|
313 | //
|
314 | // [1] Wikipedia Fixed-point arithmetic
|
315 | // http://en.wikipedia.org/wiki/Fixed-point_arithmetic
|
316 | //
|
317 | //
|
318 | // [2] http://www.mikrocontroller.net/
|
319 | //
|
320 | ////////////////////////////////////////////////////////////////////////////////
|
321 |
|
322 |
|
323 | #define inline
|
324 |
|
325 | #ifndef _FIXPOINT_H_
|
326 | #define _FIXPOINT_H_
|
327 |
|
328 | // only valid in C++, not C
|
329 | #ifdef __cplusplus
|
330 |
|
331 |
|
332 | #include <stdint.h>
|
333 | #include <inttypes.h>
|
334 | #include <math.h>
|
335 |
|
336 |
|
337 | // A prior definition of NO_STDSTRING suppresses the conversion to
|
338 | // std::string and eliminates the need #include <string>
|
339 | //
|
340 | // A prior definition of NO_STDIOSTREAM suppresses output to
|
341 | // std::ostream and input from std::istream.
|
342 |
|
343 | #ifndef NO_STDSTRING
|
344 | #include <string>
|
345 | #endif /* ifndef NO_STDSTRING */
|
346 |
|
347 | #ifndef NO_STDIOSTREAM
|
348 | #include <iostream>
|
349 | #endif /* ifndef NO_STDIOSTREAM */
|
350 |
|
351 |
|
352 | namespace Anyware
|
353 | {
|
354 |
|
355 | template< typename TBASE = int16_t,
|
356 | typename TTEMP = TBASE,
|
357 | const int LFRACTIONAL = sizeof(TBASE)/2,
|
358 | const bool ROUNDTONEAREST = true
|
359 | > class fixpoint
|
360 | {
|
361 |
|
362 | public:
|
363 |
|
364 | // this type
|
365 | typedef fixpoint< TBASE, TTEMP, LFRACTIONAL, ROUNDTONEAREST > type;
|
366 |
|
367 | //
|
368 | // constructing
|
369 | //
|
370 |
|
371 | // ctor with no arguments: 0
|
372 | fixpoint()
|
373 | : basevalue( 0 )
|
374 | {}
|
375 |
|
376 | // ctor with integral value
|
377 | fixpoint( TBASE init )
|
378 | : basevalue( LFRACTIONAL>0
|
379 | ? ( init << LFRACTIONAL )
|
380 | : ( ROUNDTONEAREST
|
381 | ? ( (((TTEMP)init)+(1<<(-LFRACTIONAL-1))) >> -LFRACTIONAL )
|
382 | : ( init >> -LFRACTIONAL )
|
383 | )
|
384 | )
|
385 | {
|
386 | }
|
387 |
|
388 | // ctor with floating point value
|
389 | fixpoint( const double &init )
|
390 | : basevalue( ldexp( init, LFRACTIONAL )
|
391 | +
|
392 | ( ROUNDTONEAREST ? ( init<0.0 ? -0.5 : +0.5 ) : 0.0 )
|
393 | )
|
394 | {
|
395 | }
|
396 |
|
397 | // ctor with a and b: initial value is a/b
|
398 | template< typename TA, typename TB > fixpoint( TA a, TB b )
|
399 |
|
400 | : basevalue( ( ( b<0 ? (void)( (a=-a), (b=-b) ) : (void)0 ),
|
401 | ( LFRACTIONAL>0
|
402 | ? ( ROUNDTONEAREST
|
403 | ? ( a>=0
|
404 | ? (((((TTEMP)a)<<LFRACTIONAL)+(b/2))/b)
|
405 | : (((((TTEMP)a)<<LFRACTIONAL)-(b/2))/b)
|
406 | )
|
407 | : (((TTEMP)a)<<LFRACTIONAL)/b
|
408 | )
|
409 | : ( ROUNDTONEAREST
|
410 | ? ( a>0
|
411 | ? ((a+(((TTEMP)b)<<(-LFRACTIONAL-1)))
|
412 | /(((TTEMP)b)<<-LFRACTIONAL))
|
413 | : ((a-b/2)/(((TTEMP)b)<<-LFRACTIONAL))
|
414 | )
|
415 | : (a/(((TTEMP)b)<<-LFRACTIONAL)) )
|
416 | )
|
417 | )
|
418 | )
|
419 | {
|
420 | }
|
421 |
|
422 |
|
423 | //
|
424 | // conversions
|
425 | //
|
426 |
|
427 | operator double() const
|
428 | {
|
429 | return ldexp( double( basevalue ), -LFRACTIONAL );
|
430 | }
|
431 |
|
432 | // TODO: take care for ROUNDTONEAREST
|
433 | #define _FIXPOINT_DEFINE_CONVERSION_TO_INTEGRAL(integraltype) \
|
434 | operator integraltype() const \
|
435 | { \
|
436 | if( LFRACTIONAL>0 ) \
|
437 | { \
|
438 | return basevalue >> LFRACTIONAL; \
|
439 | } \
|
440 | else if( LFRACTIONAL<0 ) \
|
441 | { \
|
442 | return ((integraltype)basevalue) << -LFRACTIONAL; \
|
443 | } \
|
444 | else \
|
445 | { \
|
446 | return basevalue; \
|
447 | } \
|
448 | }
|
449 |
|
450 | _FIXPOINT_DEFINE_CONVERSION_TO_INTEGRAL(int8_t);
|
451 | _FIXPOINT_DEFINE_CONVERSION_TO_INTEGRAL(int16_t);
|
452 | _FIXPOINT_DEFINE_CONVERSION_TO_INTEGRAL(int32_t);
|
453 | _FIXPOINT_DEFINE_CONVERSION_TO_INTEGRAL(int64_t);
|
454 | _FIXPOINT_DEFINE_CONVERSION_TO_INTEGRAL(uint8_t);
|
455 | _FIXPOINT_DEFINE_CONVERSION_TO_INTEGRAL(uint16_t);
|
456 | _FIXPOINT_DEFINE_CONVERSION_TO_INTEGRAL(uint32_t);
|
457 | _FIXPOINT_DEFINE_CONVERSION_TO_INTEGRAL(uint64_t);
|
458 |
|
459 | #undef _FIXPOINT_DEFINE_CONVERSION_TO_INTEGRAL
|
460 |
|
461 |
|
462 | //
|
463 | // operations
|
464 | //
|
465 |
|
466 | // !a
|
467 | bool operator!() const
|
468 | {
|
469 | return basevalue==0;
|
470 | }
|
471 |
|
472 | // prefix++: ++a returns modified value
|
473 | type &operator++()
|
474 | {
|
475 | if( LFRACTIONAL>=0 )
|
476 | {
|
477 | basevalue += 1<<LFRACTIONAL;
|
478 | }
|
479 | return *this;
|
480 | }
|
481 |
|
482 | // postfix++: a++ returns unmodified value
|
483 | type operator++( int )
|
484 | {
|
485 | type oldvalue( *this );
|
486 | ++*this;
|
487 | return oldvalue;
|
488 | }
|
489 |
|
490 | // prefix--: --a returns modified value
|
491 | type &operator--()
|
492 | {
|
493 | if( LFRACTIONAL>=0 )
|
494 | {
|
495 | basevalue += 1<<LFRACTIONAL;
|
496 | }
|
497 | return *this;
|
498 | }
|
499 |
|
500 | // postfix--: a-- returns unmodified value
|
501 | type operator--( int )
|
502 | {
|
503 | type oldvalue( *this );
|
504 | --*this;
|
505 | return oldvalue;
|
506 | }
|
507 |
|
508 | // +a does nothing
|
509 | type operator+()
|
510 | {
|
511 | return *this;
|
512 | }
|
513 |
|
514 | // -a negates
|
515 | type operator-()
|
516 | {
|
517 | type ret;
|
518 | ret.basevalue = -basevalue;
|
519 | return ret;
|
520 | }
|
521 |
|
522 | type operator*( const type &rS ) const
|
523 | {
|
524 | TTEMP tempvalue = TTEMP(basevalue) * rS.basevalue;
|
525 | if( LFRACTIONAL>0 )
|
526 | {
|
527 | if( ROUNDTONEAREST )
|
528 | {
|
529 | // get a bit away from 0 to have the result rounded instead
|
530 | // of truncating
|
531 | if( tempvalue>0 )
|
532 | {
|
533 | tempvalue += 1<<(LFRACTIONAL-1);
|
534 | }
|
535 | else if( tempvalue<0 )
|
536 | {
|
537 | tempvalue -= 1<<(LFRACTIONAL-1);
|
538 | }
|
539 | }
|
540 | tempvalue >>= LFRACTIONAL;
|
541 | }
|
542 | else if( LFRACTIONAL<0 )
|
543 | {
|
544 | tempvalue <<= -LFRACTIONAL;
|
545 | }
|
546 | type ret;
|
547 | ret.basevalue = tempvalue;
|
548 | return ret;
|
549 | }
|
550 |
|
551 | type operator/( const type &rS ) const
|
552 | {
|
553 | if( LFRACTIONAL>0 )
|
554 | {
|
555 | return type( TTEMP(basevalue)<<LFRACTIONAL,
|
556 | TTEMP(rS.basevalue)<<LFRACTIONAL
|
557 | );
|
558 | }
|
559 | else
|
560 | {
|
561 | return type( basevalue, rS.basevalue );
|
562 | }
|
563 | }
|
564 |
|
565 | type operator%( const type &rS ) const
|
566 | {
|
567 | type ret;
|
568 | ret.basevalue = basevalue % rS.basevalue;
|
569 | return ret;
|
570 | }
|
571 |
|
572 | // a+b
|
573 | type operator+( const type &rS ) const
|
574 | {
|
575 | type ret;
|
576 | ret.basevalue = basevalue + rS.basevalue;
|
577 | return ret;
|
578 | }
|
579 |
|
580 | // a-b
|
581 | type operator-( const type &rS ) const
|
582 | {
|
583 | type ret;
|
584 | ret.basevalue = basevalue - rS.basevalue;
|
585 | return ret;
|
586 | }
|
587 |
|
588 | // a<b
|
589 | bool operator<( const type &rS ) const
|
590 | {
|
591 | return basevalue<rS.basevalue;
|
592 | }
|
593 |
|
594 | // a>b
|
595 | bool operator>( const type &rS ) const
|
596 | {
|
597 | return basevalue>rS.basevalue;
|
598 | }
|
599 |
|
600 | // a<=b
|
601 | bool operator<=( const type &rS ) const
|
602 | {
|
603 | return basevalue<=rS.basevalue;
|
604 | }
|
605 |
|
606 | // a>=b
|
607 | bool operator>=( const type &rS ) const
|
608 | {
|
609 | return basevalue>=rS.basevalue;
|
610 | }
|
611 |
|
612 | // a==b
|
613 | bool operator==( const type &rS ) const
|
614 | {
|
615 | return basevalue==rS.basevalue;
|
616 | }
|
617 |
|
618 | // a!=b
|
619 | bool operator!=( const type &rS ) const
|
620 | {
|
621 | return basevalue!=rS.basevalue;
|
622 | }
|
623 |
|
624 | // a&&b
|
625 | bool operator&&( const type &rS ) const
|
626 | {
|
627 | return basevalue&&rS.basevalue;
|
628 | }
|
629 |
|
630 | // a||b
|
631 | bool operator||( const type &rS ) const
|
632 | {
|
633 | return basevalue||rS.basevalue;
|
634 | }
|
635 |
|
636 | // a=b
|
637 | template< typename T >
|
638 | const type &operator=( const T &rS )
|
639 | {
|
640 | basevalue = type( rS ).basevalue;
|
641 | return *this;
|
642 | }
|
643 |
|
644 | // a+=b
|
645 | template< typename T >
|
646 | const type &operator+=( const T &rS )
|
647 | {
|
648 | basevalue = ( *this + type( rS ) ).basevalue;
|
649 | return *this;
|
650 | }
|
651 |
|
652 | // a-=b
|
653 | template< typename T >
|
654 | const type &operator-=( const T &rS )
|
655 | {
|
656 | basevalue = ( *this - type( rS ) ).basevalue;
|
657 | return *this;
|
658 | }
|
659 |
|
660 | // a*=b
|
661 | template< typename T >
|
662 | const type &operator*=( const T &rS )
|
663 | {
|
664 | basevalue = ( *this * type( rS ) ).basevalue;
|
665 | return *this;
|
666 | }
|
667 |
|
668 | // a/=b
|
669 | template< typename T >
|
670 | const type &operator/=( const T &rS )
|
671 | {
|
672 | basevalue = ( *this / type( rS ) ).basevalue;
|
673 | return *this;
|
674 | }
|
675 |
|
676 | // a%=b
|
677 | template< typename T >
|
678 | const type &operator%=( const T &rS )
|
679 | {
|
680 | basevalue = ( *this % type( rS ) ).basevalue;
|
681 | return *this;
|
682 | }
|
683 |
|
684 |
|
685 |
|
686 |
|
687 | // returns the raw internal value
|
688 | //
|
689 | // The represented value might be calculated with
|
690 | // rawvalue/(2^scalebinaryexponent)
|
691 | TBASE getBaseValue() const
|
692 | {
|
693 | return basevalue;
|
694 | }
|
695 |
|
696 | // returns the binary exponent of the scale factor (length of
|
697 | // fractional part)
|
698 | //
|
699 | // The represented value might be calculated with
|
700 | // rawvalue/(2^scalebinaryexponent)
|
701 | int getScaleBinaryExponent() const
|
702 | {
|
703 | return LFRACTIONAL;
|
704 | }
|
705 |
|
706 | // returns the scale factor
|
707 | //
|
708 | // The represented value might be calculated with
|
709 | // rawvalue/(scale)
|
710 | double getScale() const
|
711 | {
|
712 | if( LFRACTIONAL>0 )
|
713 | {
|
714 | return double(1<<LFRACTIONAL);
|
715 | }
|
716 | else if( LFRACTIONAL<0 )
|
717 | {
|
718 | return 1.0/double(1<<-LFRACTIONAL);
|
719 | }
|
720 | else
|
721 | {
|
722 | return 1.0;
|
723 | }
|
724 | }
|
725 |
|
726 | #ifndef NO_STDIOSTREAM
|
727 |
|
728 | // Value will be converted to double for writing into stream.
|
729 | // Thus all floating point formatting from include <iomanip> like
|
730 | // std::setprecision(4) will work.
|
731 | void printToOstream( std::ostream &os ) const
|
732 | {
|
733 |
|
734 | #ifdef TESTFIXPOINT
|
735 | // test version: write internal value, scaling and resulting
|
736 | // value:
|
737 | os << "fixpoint( internal=" << basevalue
|
738 | << ", scaling=" << LFRACTIONAL
|
739 | << ", rounding=" << ROUNDTONEAREST
|
740 | << ", resulting=" << double( *this )
|
741 | << " )";
|
742 | #else
|
743 | // final version: write resulting value:
|
744 | os << double( *this );
|
745 | #endif /* ifdef TESTFIXPOINT */
|
746 | }
|
747 |
|
748 |
|
749 | void readFromIstream( std::istream &is )
|
750 | {
|
751 | double dValue;
|
752 | is >> dValue;
|
753 | *this = dValue;
|
754 | }
|
755 |
|
756 | #endif /* ifndef NO_STDIOSTREAM */
|
757 |
|
758 |
|
759 | private:
|
760 |
|
761 | TBASE basevalue;
|
762 |
|
763 |
|
764 | }; // template class fixpoint
|
765 |
|
766 |
|
767 | #ifndef NO_STDIOSTREAM
|
768 |
|
769 | template< typename TBASE,
|
770 | typename TTEMP,
|
771 | const int LFRACTIONAL,
|
772 | const bool ROUNDTONEAREST
|
773 | >
|
774 | inline std::ostream &operator<<
|
775 | ( std::ostream &os,
|
776 | const Anyware::fixpoint< TBASE, TTEMP, LFRACTIONAL, ROUNDTONEAREST > &f
|
777 | )
|
778 | {
|
779 | f.printToOstream( os );
|
780 | return os;
|
781 | }
|
782 |
|
783 | template< typename TBASE,
|
784 | typename TTEMP,
|
785 | const int LFRACTIONAL,
|
786 | const bool ROUNDTONEAREST
|
787 | >
|
788 | inline std::istream &operator>>
|
789 | ( std::istream &is,
|
790 | const Anyware::fixpoint< TBASE, TTEMP, LFRACTIONAL, ROUNDTONEAREST > &f
|
791 | )
|
792 | {
|
793 | f.readFromIstream( is );
|
794 | return is;
|
795 | }
|
796 |
|
797 | #endif /* ifndef NO_STDIOSTREAM */
|
798 |
|
799 |
|
800 | } // namespace Anyware
|
801 |
|
802 |
|
803 |
|
804 | #endif /* ifdef __cplusplus */
|
805 |
|
806 | #endif /* ifndef _FIXPOINT_H_ */
|