GnuCash  5.6-150-g038405b370+
Data Structures | Public Member Functions
GncNumeric Class Reference

The primary numeric class for representing amounts and values. More...

#include <gnc-numeric.hpp>

Public Member Functions

 GncNumeric ()
 Default constructor provides the zero value.
 
 GncNumeric (int64_t num, int64_t denom)
 Integer constructor. More...
 
 GncNumeric (GncRational rr)
 GncRational constructor. More...
 
 GncNumeric (gnc_numeric in)
 gnc_numeric constructor, used for interfacing old code. More...
 
 GncNumeric (double d)
 Double constructor. More...
 
 GncNumeric (const std::string &str, bool autoround=false)
 String constructor. More...
 
 GncNumeric (const GncNumeric &rhs)=default
 
 GncNumeric (GncNumeric &&rhs)=default
 
GncNumericoperator= (const GncNumeric &rhs)=default
 
GncNumericoperator= (GncNumeric &&rhs)=default
 
 operator gnc_numeric () const noexcept
 gnc_numeric conversion. More...
 
 operator double () const noexcept
 double conversion. More...
 
int64_t num () const noexcept
 Accessor for numerator value.
 
int64_t denom () const noexcept
 Accessor for denominator value.
 
GncNumeric operator- () const noexcept
 
GncNumeric inv () const noexcept
 
GncNumeric abs () const noexcept
 
GncNumeric reduce () const noexcept
 Return an equivalent fraction with all common factors between the numerator and the denominator removed. More...
 
template<RoundType RT>
GncNumeric convert (int64_t new_denom) const
 Convert a GncNumeric to use a new denominator. More...
 
template<RoundType RT>
GncNumeric convert_sigfigs (unsigned int figs) const
 Convert with the specified sigfigs. More...
 
std::string to_string () const noexcept
 Return a string representation of the GncNumeric. More...
 
bool is_decimal () const noexcept
 
GncNumeric to_decimal (unsigned int max_places=17) const
 Convert the numeric to have a power-of-10 denominator if possible without rounding. More...
 
void operator+= (GncNumeric b)
 
void operator-= (GncNumeric b)
 
void operator*= (GncNumeric b)
 
void operator/= (GncNumeric b)
 
int cmp (GncNumeric b)
 
int cmp (int64_t b)
 

Detailed Description

The primary numeric class for representing amounts and values.

Calculations are generally performed in 128-bit (by converting to GncRational) and reducing the result. If the result would overflow a 64-bit representation then the GncNumeric(GncRational&) constructor will call GncRational::round_to_numeric() to get the value to fit. It will not raise an exception, so in the unlikely event that you need an error instead of rounding, use GncRational directly.

Errors: Errors are signalled by exceptions as follows:

Rounding Policy: GncNumeric provides a convert() member function that object amount and value setters (and only those functions!) should call to set a number which is represented in the commodity's SCU. Since SCUs are seldom 18 digits the convert may result in rounding, which will be performed in the method specified by the arguments passed to convert(). Overflows may result in internal rounding as described earlier.

Definition at line 60 of file gnc-numeric.hpp.

Constructor & Destructor Documentation

◆ GncNumeric() [1/5]

GncNumeric::GncNumeric ( int64_t  num,
int64_t  denom 
)
inline

Integer constructor.

Unfortunately specifying a default for denom causes ambiguity errors with the other single-argument constructors on older versions of gcc, so one must always specify both arguments.

Parameters
numThe Numerator
denomThe Denominator

Definition at line 77 of file gnc-numeric.hpp.

77  :
78  m_num(num), m_den(denom) {
79  if (denom == 0)
80  throw std::invalid_argument("Attempt to construct a GncNumeric with a 0 denominator.");
81  }
int64_t num() const noexcept
Accessor for numerator value.
int64_t denom() const noexcept
Accessor for denominator value.

◆ GncNumeric() [2/5]

GncNumeric::GncNumeric ( GncRational  rr)

GncRational constructor.

This constructor will round rr's GncInt128s to fit into the int64_t members using RoundType::half-down.

Parameters
rrA GncRational.

Definition at line 71 of file gnc-numeric.cpp.

72 {
73  /* Can't use isValid here because we want to throw different exceptions. */
74  if (rr.num().isNan() || rr.denom().isNan())
75  throw std::underflow_error("Operation resulted in NaN.");
76  if (rr.num().isOverflow() || rr.denom().isOverflow())
77  throw std::overflow_error("Operation overflowed a 128-bit int.");
78  if (rr.num().isBig() || rr.denom().isBig())
79  {
80  GncRational reduced(rr.reduce());
81  rr = reduced.round_to_numeric(); // A no-op if it's already small.
82  }
83  m_num = static_cast<int64_t>(rr.num());
84  m_den = static_cast<int64_t>(rr.denom());
85 }
bool isBig() const noexcept
Definition: gnc-int128.cpp:253
GncInt128 denom() const noexcept
Denominator accessor.
GncRational reduce() const
Return an equivalent fraction with all common factors between the numerator and the denominator remov...
bool isNan() const noexcept
Definition: gnc-int128.cpp:265
Rational number class using GncInt128 for the numerator and denominator.
GncRational round_to_numeric() const
Round to fit an int64_t, finding the closest possible approximation.
GncInt128 num() const noexcept
Numerator accessor.
bool isOverflow() const noexcept
Definition: gnc-int128.cpp:259

◆ GncNumeric() [3/5]

GncNumeric::GncNumeric ( gnc_numeric  in)
inline

gnc_numeric constructor, used for interfacing old code.

This function should not be used outside of gnc-numeric.cpp.

Parameters
inA gnc_numeric.

Definition at line 97 of file gnc-numeric.hpp.

97  : m_num(in.num), m_den(in.denom)
98  {
99  if (in.denom == 0)
100  throw std::invalid_argument("Attempt to construct a GncNumeric with a 0 denominator.");
101  /* gnc_numeric has a dumb convention that a negative denominator means
102  * to multiply the numerator by the denominator instead of dividing.
103  */
104  if (in.denom < 0)
105  {
106  m_num *= -in.denom;
107  m_den = 1;
108  }
109  }

◆ GncNumeric() [4/5]

GncNumeric::GncNumeric ( double  d)

Double constructor.

Parameters
dThe double to be converted. In order to fit in an int64_t, its absolute value must be < 1e18; if its absolute value is < 1e-18 it will be represented as 0, though for practical purposes nearly all commodities will round to zero at 1e-9 or larger.

Definition at line 87 of file gnc-numeric.cpp.

87  : m_num(0), m_den(1)
88 {
89  static uint64_t max_leg_value{INT64_C(1000000000000000000)};
90  if (std::isnan(d) || fabs(d) > max_leg_value)
91  {
92  std::ostringstream msg;
93  msg << "Unable to construct a GncNumeric from " << d << ".\n";
94  throw std::invalid_argument(msg.str());
95  }
96  constexpr auto max_num = static_cast<double>(INT64_MAX);
97  auto logval = log10(fabs(d));
98  int64_t den;
99  uint8_t den_digits;
100  if (logval > 0.0)
101  den_digits = (max_leg_digits + 1) - static_cast<int>(floor(logval));
102  else
103  den_digits = max_leg_digits;
104  den = powten(den_digits);
105  auto num_d = static_cast<double>(den) * d;
106  while (fabs(num_d) > max_num && den_digits > 1)
107  {
108  den = powten(--den_digits);
109  num_d = static_cast<double>(den) * d;
110  }
111  auto num = static_cast<int64_t>(floor(num_d));
112 
113  if (num == 0)
114  return;
115  GncNumeric q(num, den);
116  auto r = q.reduce();
117  m_num = r.num();
118  m_den = r.denom();
119 }
The primary numeric class for representing amounts and values.
Definition: gnc-numeric.hpp:60
int64_t num() const noexcept
Accessor for numerator value.

◆ GncNumeric() [5/5]

GncNumeric::GncNumeric ( const std::string &  str,
bool  autoround = false 
)

String constructor.

Accepts integer values in decimal and hexadecimal. Does not accept thousands separators. If the string contains a '/' it is taken to separate the numerator and denominator; if it contains either a '.' or a ',' it is taken as a decimal point and the integers on either side will be combined and a denominator will be the appropriate power of 10. If neither is present the number will be treated as an integer and m_den will be set to 1.

Whitespace around a '/' is ignored. A correctly-formatted number will be extracted from a larger string.

Numbers that cannot be represented with int64_ts will throw std::out_of_range unless a decimal point is found (see above). A 0 denominator will cause the constructor to throw std::underflow_error. An empty string or one which contains no recognizable number will result in std::invalid_argument.

Definition at line 247 of file gnc-numeric.cpp.

Member Function Documentation

◆ abs()

GncNumeric GncNumeric::abs ( ) const
noexcept
Returns
-this if this < 0 else this.

◆ convert()

template<RoundType RT>
GncNumeric GncNumeric::convert ( int64_t  new_denom) const
inline

Convert a GncNumeric to use a new denominator.

If rounding is necessary use the indicated template specification. For example, to use half-up rounding you'd call bar = foo.convert<RoundType::half_up>(1000). If you specify RoundType::never this will throw std::domain_error if rounding is required.

Parameters
new_denomThe new denominator to convert the fraction to.
Returns
A new GncNumeric having the requested denominator.

Definition at line 193 of file gnc-numeric.hpp.

194  {
195  auto params = prepare_conversion(new_denom);
196  if (new_denom == GNC_DENOM_AUTO)
197  new_denom = m_den;
198  if (params.rem == 0)
199  return GncNumeric(params.num, new_denom);
200  return GncNumeric(round(params.num, params.den,
201  params.rem, RT2T<RT>()), new_denom);
202  }
GncNumeric()
Default constructor provides the zero value.
Definition: gnc-numeric.hpp:66
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245

◆ convert_sigfigs()

template<RoundType RT>
GncNumeric GncNumeric::convert_sigfigs ( unsigned int  figs) const
inline

Convert with the specified sigfigs.

The resulting denominator depends on the value of the GncNumeric, such that the specified significant digits are retained in the numerator and the denominator is always a power of

  1. This is of rather dubious benefit in an accounting program, but it's used in several places so it needs to be implemented.
Parameters
figsThe number of digits to use for the numerator.
Returns
A GncNumeric with the specified number of digits in the numerator and the appropriate power-of-ten denominator.

Definition at line 216 of file gnc-numeric.hpp.

217  {
218  auto new_denom(sigfigs_denom(figs));
219  auto params = prepare_conversion(new_denom);
220  if (new_denom == 0) //It had better not, but just in case...
221  new_denom = 1;
222  if (params.rem == 0)
223  return GncNumeric(params.num, new_denom);
224  return GncNumeric(round(params.num, params.den,
225  params.rem, RT2T<RT>()), new_denom);
226  }
GncNumeric()
Default constructor provides the zero value.
Definition: gnc-numeric.hpp:66

◆ inv()

GncNumeric GncNumeric::inv ( ) const
noexcept
Returns
0 if this == 0 else 1/this.

◆ is_decimal()

bool GncNumeric::is_decimal ( ) const
noexcept
Returns
true if the denominator is a power of ten, false otherwise.

◆ operator double()

GncNumeric::operator double ( ) const
noexcept

double conversion.

Use static_cast<double>(foo)

◆ operator gnc_numeric()

GncNumeric::operator gnc_numeric ( ) const
noexcept

gnc_numeric conversion.

Use static_cast<gnc_numeric>(foo)

◆ operator-()

GncNumeric GncNumeric::operator- ( ) const
noexcept
Returns
A GncNumeric with the opposite sign.

◆ reduce()

GncNumeric GncNumeric::reduce ( ) const
noexcept

Return an equivalent fraction with all common factors between the numerator and the denominator removed.

Returns
reduced GncNumeric

◆ to_decimal()

GncNumeric GncNumeric::to_decimal ( unsigned int  max_places = 17) const

Convert the numeric to have a power-of-10 denominator if possible without rounding.

Throws a std::range_error on failure; the message will explain the details.

Parameters
max_placesexponent of the largest permissible denominator.
Returns
A GncNumeric value with the new denominator.

◆ to_string()

std::string GncNumeric::to_string ( ) const
noexcept

Return a string representation of the GncNumeric.

See operator<< for details.


The documentation for this class was generated from the following files: