Warning, /office/alkimia/src/alkvalue.h.in is written in an unsupported language. File is not indexed.
0001 /*
0002 SPDX-FileCopyrightText: 2010-2021 Thomas Baumgart tbaumgart @kde.org
0003
0004 This file is part of libalkimia.
0005
0006 SPDX-License-Identifier: LGPL-2.1-or-later
0007 */
0008
0009 #ifndef ALKVALUE_H
0010 #define ALKVALUE_H
0011
0012 #include <alkimia/alk_export.h>
0013
0014 // Workaround: include before gmpxx.h to fix build with gcc-4.9
0015 /** @todo When gmp version is higher than 5.1.3, remove cstddef include */
0016 #include <cstddef>
0017 #include <@MP_HEADER@> // krazy:exclude=camelcase
0018 #include <QString>
0019 #include <QSharedDataPointer>
0020
0021 /**
0022 * This class represents a financial value within Alkimia.
0023 * It can be used to represent balances, shares, amounts etc.
0024 *
0025 * @author Thomas Baumgart
0026 */
0027 class ALK_EXPORT AlkValue
0028 {
0029 public:
0030 enum RoundingMethod {
0031 RoundNever = 0, /**<
0032 * Don't do any rounding, simply truncate and
0033 * print a warning in case of a remainder.
0034 * Otherwise the same as RoundTrunc.
0035 */
0036
0037 RoundFloor, /**<
0038 * Round to the largest integral value not
0039 * greater than @p this.
0040 * e.g. 0.5 -> 0.0 and -0.5 -> -1.0
0041 */
0042
0043 RoundCeil, /**<
0044 * Round to the smallest integral value not
0045 * less than @p this.
0046 * e.g. 0.5 -> 1.0 and -0.5 -> -0.0
0047 */
0048
0049 RoundTruncate, /**<
0050 * No rounding, simply truncate any fraction
0051 */
0052
0053 RoundPromote, /**<
0054 * Use RoundCeil for positive and RoundFloor
0055 * for negative values of @p this.
0056 * e.g. 0.5 -> 1.0 and -0.5 -> -1.0
0057 */
0058
0059 RoundHalfDown, /**<
0060 * Round up or down with the following
0061 * constraints:
0062 * 0.1 .. 0.5 -> 0.0 and 0.6 .. 0.9 -> 1.0
0063 */
0064
0065 RoundHalfUp, /**<
0066 * Round up or down with the following
0067 * constraints:
0068 * 0.1 .. 0.4 -> 0.0 and 0.5 .. 0.9 -> 1.0
0069 */
0070
0071 RoundRound /**<
0072 * Use RoundHalfDown for 0.1 .. 0.4 and
0073 * RoundHalfUp for 0.6 .. 0.9. Use RoundHalfUp
0074 * for 0.5 in case the resulting numerator
0075 * is odd, RoundHalfDown in case the resulting
0076 * numerator is even.
0077 * e.g. 0.5 -> 0.0 and 1.5 -> 2.0
0078 */
0079 };
0080
0081 // Constructors / Destructor
0082 /**
0083 * This is the standard constructor of an AlkValue object.
0084 * The value will be initialized to 0.
0085 */
0086 AlkValue();
0087
0088 /// The destructor
0089 ~AlkValue();
0090
0091 /// Copy constructor
0092 AlkValue(const AlkValue &val);
0093
0094 /**
0095 * This constructor converts an int into an AlkValue. It can
0096 * also convert a rational number when a @a denom is supplied.
0097 *
0098 * @param num numerator of the rational number
0099 * @param denom denominator of the rational number (defaults to 1)
0100 */
0101 explicit AlkValue(const int num, const unsigned int denom = 1);
0102
0103 /**
0104 * Convenience ctor for usage with mpz_class objects as numerator
0105 * and denominator.
0106 *
0107 * @param num numerator of the rational number
0108 * @param denom denominator of the rational number (defaults to 1)
0109 */
0110 explicit AlkValue(const mpz_class &num, const mpz_class &denom);
0111
0112 /**
0113 * Convenience ctor to create an AlkValue object based on an mpq_class object
0114 */
0115 explicit AlkValue(const mpq_class &val);
0116
0117 /**
0118 * This constructor converts a double into an AlkValue. In case
0119 * a @a denom is supplied with a value different from zero, the
0120 * @a val will be rounded to be based on the supplied @a denom.
0121 * e.g. val = 1.234 and denom = 100 will construct an AlkValue
0122 * of 1.23. The rounding method is @p RoundRound.
0123 *
0124 * @sa AlkValue::convertDenominator()
0125 *
0126 * @param val the double value
0127 * @param denom the denominator of the resulting AlkValue
0128 *
0129 * @note In case one wants to use the number of decimal places
0130 * to specify the length of the fractional part, use
0131 *
0132 * @code
0133 * AlkValue alk(1.234, AlkValue::precisionToDenominator(2).get_ui());
0134 * // alk == 1.23
0135 * @endcode
0136 */
0137 explicit AlkValue(const double &val, const unsigned int denom = 0);
0138
0139 /**
0140 * This constructor converts a QString into an AlkValue.
0141 * Several formats are supported:
0142 *
0143 * -# prices in the form "8 5/16"
0144 * -# our own toString() format
0145 * -# others
0146
0147 * Others may be enclosed in "(" and ")" and treated as negative.
0148 * They may start or end with a dash and treated as negative.
0149 * The decimal symbols is identified as provided in @a decimalSymbol.
0150 * All other non-numeric characters are skipped
0151 */
0152 AlkValue(const QString &str, const QChar &decimalSymbol);
0153
0154 /**
0155 * Returns the current value converted to the given @a denom (default is 100
0156 * or two digits of precision). The rounding method used is controlled by
0157 * the @a how argument and defaults to @p RoundRound.
0158 */
0159 AlkValue convertDenominator(const int denom = 100, const RoundingMethod how = RoundRound) const;
0160
0161 /**
0162 * Returns the current value converted to the given @a denom.
0163 * The rounding method used is controlled by the @a how argument
0164 * and defaults to @p RoundRound.
0165 *
0166 * @param denom The wanted denominator (defaults to 100 representing 2 digits)
0167 * @param how The rounding method. See AlkValue::RoundingMethod for details
0168 */
0169 AlkValue convertDenominator(const mpz_class denom, const AlkValue::RoundingMethod how = AlkValue::RoundRound) const;
0170
0171 /**
0172 * This is a convenience function for convertDenom but instead of providing
0173 * the new denominator one provides the number of digits for the @a precision.
0174 * This value defaults to 2. The rounding method used is controlled by
0175 * the @a how argument and defaults to @p RoundRound.
0176 */
0177 AlkValue convertPrecision(const int precision = 2, const RoundingMethod how = RoundRound) const;
0178
0179 // assignment operators
0180 const AlkValue & operator=(const AlkValue &val);
0181 const AlkValue & operator=(int num);
0182 const AlkValue & operator=(double num);
0183 const AlkValue & operator=(const QString &str);
0184
0185 // comparison
0186 bool operator==(const AlkValue &val) const;
0187 bool operator!=(const AlkValue &val) const;
0188 bool operator<(const AlkValue &val) const;
0189 bool operator>(const AlkValue &val) const;
0190 bool operator<=(const AlkValue &val) const;
0191 bool operator>=(const AlkValue &val) const;
0192
0193 // calculation
0194 AlkValue operator+(const AlkValue &summand) const;
0195 AlkValue operator-(const AlkValue &minuend) const;
0196 AlkValue operator*(const AlkValue &factor) const;
0197 AlkValue operator/(const AlkValue &divisor) const;
0198 AlkValue operator%(int operand) const;
0199
0200 AlkValue operator*(int factor) const;
0201
0202 // unary operators
0203 AlkValue operator-() const;
0204 AlkValue & operator+= (const AlkValue &val);
0205 AlkValue & operator-= (const AlkValue &val);
0206 AlkValue & operator/= (const AlkValue &val);
0207 AlkValue & operator*= (const AlkValue &val);
0208
0209 // functions
0210
0211 /// @return the absolute value of the AlkValue
0212 AlkValue abs() const;
0213
0214 /// @return QString representation in form '[-]num/denom'.
0215 QString toString() const;
0216
0217 double toDouble() const;
0218
0219 /**
0220 * This method transforms the AlkValue into its canonicalized
0221 * form by reducing it to the smallest denominator. Example:
0222 * 25/100 will be converted to 1/4. Use this function at the
0223 * end of a longer calculation as all AlkValue methods require
0224 * the object to be in the canonicalized form. For speed purposes
0225 * the conversion is not performed before each operation.
0226 *
0227 * @return const reference to the object
0228 */
0229 const AlkValue& canonicalize();
0230
0231 /// convert a denominator to a precision
0232 /// e.g. 100 -> 2, 1000 -> 3
0233 /// in case of a negative @a denom, the function returns 0
0234 static mpz_class denominatorToPrecision(mpz_class denom);
0235
0236 /// convert a precision to the corresponding denominator
0237 /// e.g. 2 -> 100, 4 -> 10000
0238 /// in case of a negative @a prec, the function returns 1
0239 static mpz_class precisionToDenominator(mpz_class prec);
0240
0241 protected:
0242 /// \internal unit test class
0243 friend class AlkValueTest;
0244
0245 /// provides an access method to the private value storage
0246 /// for derived classes
0247 const mpq_class &valueRef() const;
0248 mpq_class &valueRef();
0249
0250 private:
0251 /// \internal d-pointer class.
0252 class Private;
0253 /// \internal d-pointer instance.
0254 QSharedDataPointer<Private> d;
0255 /// \internal shared zero value.
0256 static QSharedDataPointer<AlkValue::Private>& sharedZero();
0257
0258 // The following methods are not implemented (yet)
0259 // ALKIMIA_EXPORT friend QDataStream &operator<<(QDataStream &, const AlkValue &);
0260 // ALKIMIA_EXPORT friend QDataStream &operator>>(QDataStream &, AlkValue &);
0261 };
0262
0263 #endif
0264