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 */