File indexing completed on 2024-05-12 15:58:16

0001 /*
0002  *  SPDX-FileCopyrightText: 2012 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __KIS_FIXED_POINT_MATHS_H
0008 #define __KIS_FIXED_POINT_MATHS_H
0009 
0010 #include <boost/operators.hpp>
0011 #include <QDataStream>
0012 
0013 class KisFixedPoint : boost::ordered_field_operators<KisFixedPoint>
0014 {
0015 public:
0016     KisFixedPoint()
0017         : d(0){};
0018 
0019     KisFixedPoint(int iValue)
0020         : d(iValue * 256)
0021     {
0022     }
0023 
0024     KisFixedPoint(qreal fValue)
0025         : d(static_cast<int>(fValue * 256))
0026     {
0027     }
0028 
0029     qint32 toInt() const {
0030         return d >= 0 ? d >> 8 : -((-d) >> 8);
0031     }
0032 
0033     qint32 toIntRound() const {
0034         return d >= 0 ? (d + (1 << 7)) >> 8 : -((-d + (1 << 7)) >> 8);
0035     }
0036 
0037     qint32 toIntCeil() const {
0038         return d >= 0 ? (d + ((1 << 8) - 1)) >> 8 : -((-d) >> 8);
0039     }
0040 
0041     qint32 toIntFloor() const {
0042         return d >= 0 ? d >> 8 : -((-d + ((1 << 8) - 1)) >> 8);
0043     }
0044 
0045     qreal toFloat() const {
0046         return qreal(d) / qreal(1 << 8);
0047     }
0048 
0049     KisFixedPoint& from256Frac(qint32 v) {
0050         d = v;
0051         return *this;
0052     }
0053 
0054     qint32 to256Frac() const {
0055         return d;
0056     }
0057 
0058     KisFixedPoint& inc256Frac() {
0059         d++;
0060         return *this;
0061     }
0062 
0063     KisFixedPoint& dec256Frac() {
0064         d--;
0065         return *this;
0066     }
0067 
0068     bool isInteger() const {
0069         return !(d & ((1 << 8) -1 ));
0070     }
0071 
0072     bool operator<(const KisFixedPoint& x) const {
0073         return d < x.d;
0074     }
0075 
0076     bool operator==(const KisFixedPoint& x) const {
0077         return d == x.d;
0078     }
0079 
0080     KisFixedPoint& operator+=(const KisFixedPoint& x) {
0081         d += x.d;
0082         return *this;
0083     }
0084 
0085     KisFixedPoint& operator-=(const KisFixedPoint& x) {
0086         d -= x.d;
0087         return *this;
0088     }
0089 
0090     KisFixedPoint &operator*=(const KisFixedPoint &x)
0091     {
0092         /**
0093          * Until C++20 `d >>= 8` is "implementation defined" for negative `d`.
0094          * But we have a unittest that confirms that the our compiler handles
0095          * that in an expected way
0096          */
0097 
0098         d *= x.d;
0099         d >>= 8;
0100         return *this;
0101     }
0102 
0103     KisFixedPoint &operator/=(const KisFixedPoint &x)
0104     {
0105         /**
0106          * Until C++20 `d <<= 8` is an "undefined behavior" for negative `d`.
0107          * But we have a unittest that confirms that the our compiler handles
0108          * that in an expected way
0109          */
0110 
0111         d *= 256;
0112         d /= x.d;
0113         return *this;
0114     }
0115 
0116 private:
0117     friend KisFixedPoint operator-(KisFixedPoint x);
0118     friend QDebug operator<<(QDebug dbg, const KisFixedPoint &v);
0119 
0120 private:
0121     qint32 d;
0122 };
0123 
0124 inline KisFixedPoint operator-(KisFixedPoint x) {
0125     x.d = -x.d;
0126     return x;
0127 }
0128 
0129 QDebug operator<<(QDebug dbg, const KisFixedPoint &v) {
0130     dbg.nospace() << v.toFloat() << " (d = " << v.d << ")";
0131     return dbg.space();
0132 }
0133 
0134 #endif /* __KIS_FIXED_POINT_MATHS_H */