mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-25 18:30:23 -06:00
276 lines
9.8 KiB
C++
276 lines
9.8 KiB
C++
/********************************************************************
|
|
* qofmath128.h -- an 128-bit integer library *
|
|
* Copyright (C) 2004 Linas Vepstas <linas@linas.org> *
|
|
* Copyright (C) 2014 John Ralls <jralls@ceridwen.us> *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU General Public License as *
|
|
* published by the Free Software Foundation; either version 2 of *
|
|
* the License, or (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License*
|
|
* along with this program; if not, contact: *
|
|
* *
|
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
|
* *
|
|
*******************************************************************/
|
|
|
|
#ifndef GNCINT128_H
|
|
#define GNCINT128_H
|
|
|
|
#ifndef __STDC_LIMIT_MACROS
|
|
#define __STDC_LIMIT_MACROS 1
|
|
#endif
|
|
#ifndef __STDC_CONSTANT_MACROS
|
|
#define __STDC_CONSTANT_MACROS 1
|
|
#endif
|
|
#ifndef __STDC_FORMAT_MACROS
|
|
#define __STDC_FORMAT_MACROS 1
|
|
#endif
|
|
#include <inttypes.h>
|
|
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <ostream>
|
|
#include <type_traits>
|
|
|
|
//using std::string;
|
|
/** @addtogroup GncInt128
|
|
* @ingroup QOF
|
|
* @{
|
|
* @brief provides a 125-bit int as a base class for GncNumeric.
|
|
*
|
|
* In order to make space for the status flags the upper leg is limited to
|
|
* 0x1fffffffffffffff. Attempting to construct a GncInt128 with a larger upper
|
|
* leg will throw a std::overflow_error.
|
|
*
|
|
* All the usual operators are provided. Only the constructors and explicit
|
|
* integer conversions throw; all other errors are indicated by the overflow and
|
|
* NaN ("Not a Number") flags. Note that performing any operation on an
|
|
* overflowed or NaN Gncint128 will yield an overflowed or NaN result, so
|
|
* calling routines need not check until the end of a chained calculation.
|
|
* GncInt128 uses implicit copy and move constructors and implicit destructor.
|
|
*/
|
|
class GncInt128
|
|
{
|
|
uint64_t m_hi;
|
|
uint64_t m_lo;
|
|
|
|
public:
|
|
static const unsigned int flagbits = 3;
|
|
static const unsigned int numlegs = 2;
|
|
static const unsigned int legbits = 64;
|
|
static const unsigned int maxbits = legbits * numlegs - flagbits;
|
|
|
|
enum // Values for m_flags
|
|
{
|
|
pos = 0,
|
|
neg = 1,
|
|
overflow = 2,
|
|
NaN = 4
|
|
};
|
|
/** @addtogroup Constructors Constructors
|
|
* Constructors are templated so that a GncInt128 can be constructed from any
|
|
* arbitrary integer type or pair of integer types.
|
|
* @note If the two parameters are of differing sign, it's taken to
|
|
* mean that the lower magnitude is *reducing* the magnitude of the
|
|
* upper, so the lower magnitude will be subtracted from UINT64_MAX to
|
|
* obtain the lower limb value.
|
|
* @{
|
|
*/
|
|
/** Default constructor. Makes 0. */
|
|
GncInt128();
|
|
template <typename T,
|
|
std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
|
GncInt128(T lower) : GncInt128(INT64_C(0), static_cast<int64_t>(lower))
|
|
{}
|
|
GncInt128(uint64_t lower) : GncInt128 {UINT64_C(0), lower} {}
|
|
/** Double-integer constructor template.
|
|
*/
|
|
template <typename T, typename U,
|
|
std::enable_if_t<(std::is_integral<T>::value &&
|
|
std::is_integral<U>::value), bool> = true>
|
|
GncInt128(T upper, U lower, unsigned char flags = '\0') :
|
|
GncInt128 {static_cast<int64_t>(upper),
|
|
static_cast<int64_t>(lower), flags} {}
|
|
|
|
GncInt128 (int64_t upper, int64_t lower, unsigned char flags = '\0');
|
|
template <typename T,
|
|
std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
|
GncInt128(T upper, uint64_t lower) :
|
|
GncInt128 {static_cast<int64_t>(upper), lower} {}
|
|
|
|
GncInt128 (int64_t upper, uint64_t lower, unsigned char flags = '\0');
|
|
GncInt128 (uint64_t upper, uint64_t lower, unsigned char flags = '\0');
|
|
/** @} */
|
|
/**
|
|
* Clear the object.
|
|
*
|
|
* Sets all member variables to zero.
|
|
* @return A reference to the object for chaining.
|
|
*/
|
|
GncInt128& zero() noexcept;
|
|
|
|
/**
|
|
* Compare function.
|
|
*
|
|
* @return -1 if the object is less than the parameter, 0 if they're
|
|
* equal, and 1 if the object is greater.
|
|
*/
|
|
int cmp (const GncInt128& b) const noexcept;
|
|
|
|
/**
|
|
* Computes the Greatest Common Divisor between the object and parameter
|
|
*
|
|
* @return A GncInt128 having the GCD.
|
|
*/
|
|
GncInt128 gcd (GncInt128 b) const noexcept;
|
|
/**
|
|
* Computes the Least Common Multiple between the object and parameter
|
|
*
|
|
* @return A GncInt128 having the LCM.
|
|
*/
|
|
GncInt128 lcm (const GncInt128& b) const noexcept;
|
|
|
|
/**
|
|
* Computes the object raised to the parameter's power
|
|
*
|
|
* @param b The power to raise this to. No point in taking a GncInt128, any
|
|
* value greater than 128 would overflow on any value other than 1.
|
|
* @return A GncInt128
|
|
*/
|
|
GncInt128 pow (unsigned int n) const noexcept;
|
|
|
|
/**
|
|
* Computes a quotient and a remainder, passed as reference parameters.
|
|
*
|
|
* 'this' is the dividend. The quotient and remainder args must be initialized
|
|
* to zero.
|
|
* @param d The divisor
|
|
* @param q The quotient; will be NaN if divisor = 0
|
|
* @param r The remainder; will be 0 if divisor = 0
|
|
*/
|
|
void div (const GncInt128& d, GncInt128& q, GncInt128& r) const noexcept;
|
|
|
|
/**
|
|
* Explicit conversion to int64_t.
|
|
*
|
|
* @return A int64_t
|
|
* @throws std::overflow_error if the object's value is > INT64_MAX or NaN.
|
|
* @throws std::underflow_error if the object's value is < INT64_MIN
|
|
*/
|
|
explicit operator int64_t() const;
|
|
/**
|
|
* Explicit conversion to uint64_t.
|
|
*
|
|
* @return A uint64_t
|
|
* @throws std::overflow_error if the object's value is > UINT64_MAX or NaN.
|
|
* @throws std::underflow_error if the object's value is < 0.
|
|
*/
|
|
explicit operator uint64_t() const;
|
|
|
|
/**
|
|
* @return true if the object value is < 0
|
|
*/
|
|
bool isNeg () const noexcept;
|
|
/**
|
|
* @return true if the object value is > INT64_MAX or < INT64_MIN
|
|
*/
|
|
bool isBig () const noexcept;
|
|
/**
|
|
* @return true if a calculation has produced a result of larger
|
|
* magnitude than can be contained in the 128 bits available.
|
|
*/
|
|
bool isOverflow () const noexcept;
|
|
/**
|
|
* @return true if an illegal calculation has occurred.
|
|
*/
|
|
bool isNan () const noexcept;
|
|
/**
|
|
* @return true if the object represents 0.
|
|
*/
|
|
bool isZero() const noexcept;
|
|
/**
|
|
* @return true if neither the overflow nor nan flags are set.
|
|
*/
|
|
bool valid() const noexcept;
|
|
|
|
/**
|
|
* @return the number of bits used to represent the value
|
|
*/
|
|
unsigned int bits() const noexcept;
|
|
|
|
/**
|
|
* Fills a supplied buffer with a representation of the number in base 10. If
|
|
* the GncInt128 is overflowed or NaN it will contain the words "Overflow" or
|
|
* "NaN" respectively.
|
|
*
|
|
* @param buf char[41], 39 digits plus sign and trailing 0.
|
|
* @return pointer to the buffer for convenience
|
|
*/
|
|
char* asCharBufR(char* buf, uint32_t size) const noexcept;
|
|
|
|
GncInt128 abs() const noexcept;
|
|
|
|
GncInt128 operator-() const noexcept;
|
|
explicit operator bool() const noexcept;
|
|
|
|
GncInt128& operator++ () noexcept;
|
|
GncInt128& operator++ (int) noexcept;
|
|
GncInt128& operator-- () noexcept;
|
|
GncInt128& operator-- (int) noexcept;
|
|
GncInt128& operator<<= (unsigned int i) noexcept;
|
|
GncInt128& operator>>= (unsigned int i) noexcept;
|
|
GncInt128& operator+= (const GncInt128& b) noexcept;
|
|
GncInt128& operator-= (const GncInt128& b) noexcept;
|
|
GncInt128& operator*= (const GncInt128& b) noexcept;
|
|
GncInt128& operator/= (const GncInt128& b) noexcept;
|
|
GncInt128& operator%= (const GncInt128& b) noexcept;
|
|
GncInt128& operator&= (const GncInt128& b) noexcept;
|
|
GncInt128& operator|= (const GncInt128& b) noexcept;
|
|
GncInt128& operator^= (const GncInt128& b) noexcept;
|
|
|
|
};
|
|
|
|
static const GncInt128 k_gncint128_Max {UINT64_MAX, UINT64_MAX, GncInt128::pos};
|
|
static const GncInt128 k_gncint128_Min {UINT64_MAX, UINT64_MAX, GncInt128::neg};
|
|
|
|
GncInt128 operator+ (GncInt128 a, const GncInt128& b) noexcept;
|
|
GncInt128 operator- (GncInt128 a, const GncInt128& b) noexcept;
|
|
GncInt128 operator* (GncInt128 a, const GncInt128& b) noexcept;
|
|
GncInt128 operator/ (GncInt128 a, const GncInt128& b) noexcept;
|
|
GncInt128 operator% (GncInt128 a, const GncInt128& b) noexcept;
|
|
GncInt128 operator& (GncInt128 a, const GncInt128& b) noexcept;
|
|
GncInt128 operator| (GncInt128 a, const GncInt128& b) noexcept;
|
|
GncInt128 operator^ (GncInt128 a, const GncInt128& b) noexcept;
|
|
GncInt128 operator<< (GncInt128 a, unsigned int b) noexcept;
|
|
GncInt128 operator>> (GncInt128 a, unsigned int b) noexcept;
|
|
|
|
bool operator== (const GncInt128& a, const GncInt128& b) noexcept;
|
|
bool operator!= (const GncInt128& a, const GncInt128& b) noexcept;
|
|
bool operator<= (const GncInt128& a, const GncInt128& b) noexcept;
|
|
bool operator>= (const GncInt128& a, const GncInt128& b) noexcept;
|
|
bool operator< (const GncInt128& a, const GncInt128& b) noexcept;
|
|
bool operator> (const GncInt128& a, const GncInt128& b) noexcept;
|
|
|
|
std::ostream& operator<< (std::ostream&, const GncInt128&) noexcept;
|
|
|
|
/** Compute the greatest common denominator of two integers
|
|
*/
|
|
GncInt128 gcd (int64_t a, int64_t b);
|
|
|
|
/** Compute the least common multiple of two integers
|
|
*/
|
|
GncInt128 lcm (int64_t a, int64_t b);
|
|
|
|
#endif //GNCINT128_H
|
|
|
|
/** @} */
|