// Copyright (c) 2003 // Kevin Atkinson // // Permission to use, copy, modify, distribute and sell this software // and its documentation for any purpose is hereby granted without // fee, provided that the above copyright notice appear in all copies // and that both that copyright notice and this permission notice // appear in supporting documentation. Kevin Atkinson makes no // representations about the suitability of this software for any // purpose. It is provided "as is" without express or implied // warranty. #include template static inline T pow2(T v, int e) { return e < 0 ? v >> -e : v << e; } template class FixedPoint { public: T val; static const int exponent = EXP; typedef T BaseType; FixedPoint() : val(0) {} FixedPoint(T v) : val(pow2(v,-EXP)) {} FixedPoint(double v0) { int e; double v = std::frexp(v0,&e); val = static_cast(std::ldexp(v,e-EXP)); } FixedPoint(T v, int e) : val(pow2(v, e - EXP)) {} FixedPoint(const FixedPoint & v) : val(v.val) {} template FixedPoint(const FixedPoint & v) : val(pow2(v.val, E2 - EXP)) {} operator T () const {return pow2(val,EXP);} operator double () const {return std::ldexp(static_cast(val), EXP);} FixedPoint operator- () const {return FixedPoint(-val, EXP);} static FixedPoint frac(T x, T y) {return FixedPoint(pow2(x, -EXP) / y, EXP);} // Use these static members to force the return type to a particular // fixed point type template static FixedPoint add(FixedPoint x, FixedPoint y) {return FixedPoint(pow2(x.val, E1-EXP) + pow2(y.val, E2-EXP), EXP);} template static FixedPoint sub(FixedPoint x, FixedPoint y) {return FixedPoint(pow2(x.val, E1-EXP) - pow2(y.val, E2-EXP), EXP);} template static FixedPoint mul(FixedPoint x, FixedPoint y) {return FixedPoint(x.val * y.val, E1 + E2);} template static FixedPoint div(FixedPoint x, FixedPoint y) {return FixedPoint(x.val / y.val, E1 - E2);} }; // // Comparision // template static inline bool operator== (FixedPoint x, FixedPoint y) { return x.val == y.val; } template static inline bool operator!= (FixedPoint x, FixedPoint y) { return x.val != y.val; } template static inline bool operator< (FixedPoint x, FixedPoint y) { return x.val < y.val; } template static inline bool operator> (FixedPoint x, FixedPoint y) { return x.val > y.val; } template static inline bool operator<= (FixedPoint x, FixedPoint y) { return x.val <= y.val; } template static inline bool operator>= (FixedPoint x, FixedPoint y) { return x.val >= y.val; } // // Arithmetic // template static inline FixedPoint operator+ (FixedPoint x, FixedPoint y) { return FixedPoint(x.val + y.val, E); } template static inline FixedPoint operator- (FixedPoint x, FixedPoint y) { return FixedPoint(x.val - y.val, E); } template static inline FixedPoint operator* (FixedPoint x, FixedPoint y) { return FixedPoint(x.val * y.val, 2*E); } template static inline FixedPoint operator/ (FixedPoint x, FixedPoint y) { return FixedPoint(x.val / y.val, -E); } template static inline FixedPoint operator<< (FixedPoint x, int e) { return FixedPoint(x.val << e, E); } template static inline FixedPoint operator>> (FixedPoint x, int e) { return FixedPoint(x.val >> e, E); } // // Diffrent Type // // // For addition and subtraction the the best exponent for the return // type is non-obvious. So I just used the first one. Use the // static members add and sub for control over the return type // template static inline FixedPoint operator+ (FixedPoint x, FixedPoint y) { return FixedPoint(x.val + pow2(y.val, E2 - E1), E1); } template static inline FixedPoint operator- (FixedPoint x, FixedPoint y) { return FixedPoint(x.val - pow2(y.val, E2 - E1), E1); } template static inline FixedPoint operator* (FixedPoint x, FixedPoint y) { return FixedPoint(x.val * y.val, E1 + E2); } template static inline FixedPoint operator/ (FixedPoint x, FixedPoint y) { return FixedPoint(x.val / y.val, E1-E2); } // Implementing arithmatic when the underlying type is not the same is // rather tricky. What should the return type be. It should be // typeof(T1 T2) but typeof is GNU extension. // // If you want to avoid the loss of information than it is very difficult // the answer no only depends on T1 and T2 but also E1 and E2