LCOV - code coverage report
Current view: top level - libgnucash/engine - gnc-numeric.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 59.4 % 761 452
Test Date: 2025-03-30 14:51:15 Functions: 88.5 % 61 54
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /********************************************************************
       2                 :             :  * gnc-numeric.c -- an exact-number library for accounting use      *
       3                 :             :  * Copyright (C) 2000 Bill Gribble                                  *
       4                 :             :  * Copyright (C) 2004 Linas Vepstas <linas@linas.org>               *
       5                 :             :  *                                                                  *
       6                 :             :  * This program is free software; you can redistribute it and/or    *
       7                 :             :  * modify it under the terms of the GNU General Public License as   *
       8                 :             :  * published by the Free Software Foundation; either version 2 of   *
       9                 :             :  * the License, or (at your option) any later version.              *
      10                 :             :  *                                                                  *
      11                 :             :  * This program is distributed in the hope that it will be useful,  *
      12                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
      13                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
      14                 :             :  * GNU General Public License for more details.                     *
      15                 :             :  *                                                                  *
      16                 :             :  * You should have received a copy of the GNU General Public License*
      17                 :             :  * along with this program; if not, contact:                        *
      18                 :             :  *                                                                  *
      19                 :             :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      20                 :             :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      21                 :             :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      22                 :             :  *                                                                  *
      23                 :             :  *******************************************************************/
      24                 :             : 
      25                 :             : #include <glib.h>
      26                 :             : 
      27                 :             : #include <cmath>
      28                 :             : #include <cstdio>
      29                 :             : #include <cstdlib>
      30                 :             : #include <cstring>
      31                 :             : #include <cstdint>
      32                 :             : #include <sstream>
      33                 :             : #include <boost/regex.hpp>
      34                 :             : #include <boost/regex/icu.hpp>
      35                 :             : #include <boost/locale/encoding_utf.hpp>
      36                 :             : 
      37                 :             : #include <config.h>
      38                 :             : #include <stdexcept>
      39                 :             : #include <stdint.h>
      40                 :             : #include "gnc-int128.hpp"
      41                 :             : #include "qof.h"
      42                 :             : 
      43                 :             : #include "gnc-numeric.hpp"
      44                 :             : #include "gnc-rational.hpp"
      45                 :             : 
      46                 :             : #include <optional>
      47                 :             : #include <charconv>
      48                 :             : 
      49                 :             : static QofLogModule log_module = "qof";
      50                 :             : 
      51                 :             : static const uint8_t max_leg_digits{18};
      52                 :             : static const int64_t pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
      53                 :             :                                10000000, 100000000, 1000000000,
      54                 :             :                                INT64_C(10000000000), INT64_C(100000000000),
      55                 :             :                                INT64_C(1000000000000), INT64_C(10000000000000),
      56                 :             :                                INT64_C(100000000000000),
      57                 :             :                                INT64_C(1000000000000000),
      58                 :             :                                INT64_C(10000000000000000),
      59                 :             :                                INT64_C(100000000000000000),
      60                 :             :                                INT64_C(1000000000000000000)};
      61                 :             : #define POWTEN_OVERFLOW -5
      62                 :             : 
      63                 :             : int64_t
      64                 :       51452 : powten (unsigned int exp)
      65                 :             : {
      66                 :       51452 :     if (exp > max_leg_digits)
      67                 :        1037 :         exp = max_leg_digits;
      68                 :       51452 :     return pten[exp];
      69                 :             : }
      70                 :             : 
      71                 :      267497 : GncNumeric::GncNumeric(GncRational rr)
      72                 :             : {
      73                 :             :     /* Can't use isValid here because we want to throw different exceptions. */
      74                 :      267497 :     if (rr.num().isNan() || rr.denom().isNan())
      75                 :           0 :         throw std::underflow_error("Operation resulted in NaN.");
      76                 :      267497 :     if (rr.num().isOverflow() || rr.denom().isOverflow())
      77                 :           0 :         throw std::overflow_error("Operation overflowed a 128-bit int.");
      78                 :      267497 :     if (rr.num().isBig() || rr.denom().isBig())
      79                 :             :     {
      80                 :          66 :         GncRational reduced(rr.reduce());
      81                 :          66 :         rr = reduced.round_to_numeric(); // A no-op if it's already small.
      82                 :             :     }
      83                 :      267469 :     m_num = static_cast<int64_t>(rr.num());
      84                 :      267469 :     m_den = static_cast<int64_t>(rr.denom());
      85                 :      267469 : }
      86                 :             : 
      87                 :         369 : GncNumeric::GncNumeric(double d) : m_num(0), m_den(1)
      88                 :             : {
      89                 :             :     static uint64_t max_leg_value{INT64_C(1000000000000000000)};
      90                 :         369 :     if (std::isnan(d) || fabs(d) > max_leg_value)
      91                 :             :     {
      92                 :           0 :         std::ostringstream msg;
      93                 :           0 :         msg << "Unable to construct a GncNumeric from " << d << ".\n";
      94                 :           0 :         throw std::invalid_argument(msg.str());
      95                 :           0 :     }
      96                 :         369 :     constexpr auto max_num = static_cast<double>(INT64_MAX);
      97                 :         369 :     auto logval = log10(fabs(d));
      98                 :             :     int64_t den;
      99                 :             :     uint8_t den_digits;
     100                 :         369 :     if (logval > 0.0)
     101                 :         340 :         den_digits = (max_leg_digits + 1) - static_cast<int>(floor(logval));
     102                 :             :     else
     103                 :          29 :         den_digits = max_leg_digits;
     104                 :         369 :     den = powten(den_digits);
     105                 :         369 :     auto num_d = static_cast<double>(den) * d;
     106                 :         653 :     while (fabs(num_d) > max_num && den_digits > 1)
     107                 :             :     {
     108                 :         284 :         den = powten(--den_digits);
     109                 :         284 :         num_d = static_cast<double>(den) * d;
     110                 :             :     }
     111                 :         369 :     auto num = static_cast<int64_t>(floor(num_d));
     112                 :             : 
     113                 :         369 :     if (num == 0)
     114                 :           6 :         return;
     115                 :         363 :     GncNumeric q(num, den);
     116                 :         363 :     auto r = q.reduce();
     117                 :         363 :     m_num = r.num();
     118                 :         363 :     m_den = r.denom();
     119                 :             : }
     120                 :             : 
     121                 :             : using boost::regex;
     122                 :             : using boost::u32regex;
     123                 :             : using boost::regex_search;
     124                 :             : using boost::u32regex_search;
     125                 :             : using boost::smatch;
     126                 :             : 
     127                 :             : 
     128                 :             : static std::pair<int64_t, int64_t>
     129                 :          14 : reduce_number_pair(std::pair<GncInt128, GncInt128>num_pair,
     130                 :             :                    const std::string& num_str, bool autoround)
     131                 :             : {
     132                 :          14 :     auto [n, d] = num_pair;
     133                 :          14 :     if (!autoround && n.isBig()) {
     134                 :           0 :         std::ostringstream errmsg;
     135                 :             :         errmsg << "Decimal string " << num_str
     136                 :           0 :                << "can't be represented in a GncNumeric without rounding.";
     137                 :           0 :         throw std::overflow_error(errmsg.str());
     138                 :           0 :     }
     139                 :          14 :     while (n.isBig() && d > 0) {
     140                 :           0 :         n >>= 1;
     141                 :           0 :         d >>= 1;
     142                 :             :     }
     143                 :          14 :     if (n.isBig()) // Shouldn't happen, of course
     144                 :             :     {
     145                 :           0 :         std::ostringstream errmsg;
     146                 :             :         errmsg << "Decimal string " << num_str
     147                 :             :                << " can't be represented in a GncNumeric, even after reducing "
     148                 :           0 :             "denom to "
     149                 :           0 :                << d;
     150                 :           0 :         throw std::overflow_error(errmsg.str());
     151                 :           0 :     }
     152                 :          14 :     return std::make_pair(static_cast<int64_t>(n), static_cast<int64_t>(d));
     153                 :             : }
     154                 :             : 
     155                 :             : static std::pair<GncInt128, int64_t>
     156                 :          14 : numeric_from_decimal_match(const std::string& integer, const std::string& decimal)
     157                 :             : {
     158                 :          14 :     auto neg = (!integer.empty() && integer[0] == '-');
     159                 :          14 :     GncInt128 high((neg && integer.length() > 1) || (!neg && !integer.empty())
     160                 :          13 :                    ? stoll(integer)
     161                 :          28 :                    : 0);
     162                 :          14 :     GncInt128 low{ decimal.empty() ? 0 : stoll(decimal)};
     163                 :          14 :     auto exp10 = decimal.length();
     164                 :          14 :     int64_t d = powten(exp10);
     165                 :          14 :     GncInt128 n = high * d + (neg ? -low : low);
     166                 :          14 :     while (exp10 > max_leg_digits) {
     167                 :             :         /* If the arg to powten is bigger than max_leg_digits
     168                 :             :            it returns 10**max_leg_digits so reduce exp10 by
     169                 :             :            that amount */
     170                 :           0 :         n = n / powten(exp10 - max_leg_digits);
     171                 :           0 :         exp10 -= max_leg_digits;
     172                 :             :     }
     173                 :          28 :     return std::make_pair(n, d);
     174                 :             : }
     175                 :             : 
     176                 :             : static std::pair<GncInt128, GncInt128>
     177                 :           0 : numeric_from_scientific_match(smatch &m)
     178                 :             : {
     179                 :           0 :     int exp{m[4].matched ? stoi(m[4].str()) : 0};
     180                 :           0 :     auto neg_exp{exp < 0};
     181                 :           0 :     exp = neg_exp ? -exp : exp;
     182                 :           0 :     if (exp >= max_leg_digits)
     183                 :             :     {
     184                 :           0 :         std::ostringstream errmsg;
     185                 :           0 :         errmsg << "Exponent " << m[3].str() << " in match " << m[0].str()
     186                 :           0 :                << " exceeds range that GnuCash can parse.";
     187                 :           0 :         throw std::overflow_error(errmsg.str());
     188                 :           0 :     }
     189                 :             : 
     190                 :           0 :     GncInt128 num, denom;
     191                 :           0 :     auto mult = powten(exp);
     192                 :             : 
     193                 :           0 :     if (m[1].matched)
     194                 :             :     {
     195                 :           0 :         denom = neg_exp ? mult : 1;
     196                 :           0 :         num = neg_exp ? stoll(m[1].str()) : mult * stoll(m[1].str());
     197                 :             :     }
     198                 :             :     else
     199                 :             :     {
     200                 :           0 :         auto [d_num, d_denom] = numeric_from_decimal_match(m[2].str(), m[3].str());
     201                 :             : 
     202                 :           0 :         if (neg_exp || d_denom > mult)
     203                 :             :         {
     204                 :           0 :             num = d_num;
     205                 :           0 :             denom = neg_exp ? d_denom * mult : d_denom / mult;
     206                 :             :         }
     207                 :             :         else
     208                 :             :         {
     209                 :           0 :             num = d_num * mult / d_denom;
     210                 :           0 :             denom = 1;
     211                 :             :         }
     212                 :             :     }
     213                 :           0 :     return std::make_pair(num, denom);
     214                 :             : }
     215                 :             : 
     216                 :             : static std::optional<gnc_numeric>
     217                 :        5162 : fast_numeral_rational (const char* str)
     218                 :             : {
     219                 :        5162 :     if (!str || !str[0])
     220                 :           1 :         return {};
     221                 :             : 
     222                 :             :     // because minint64 = -9223372036854775808 and has 20 characters,
     223                 :             :     // the maximum strlen to handle is 20+19+1 = 40. 48 is a nice
     224                 :             :     // number in 64-bit.
     225                 :        5161 :     auto end_ptr{(const char*)memchr (str, '\0', 48)};
     226                 :        5161 :     if (!end_ptr)
     227                 :           0 :         return {};
     228                 :             : 
     229                 :        5161 :     int64_t num, denom{};
     230                 :        5161 :     auto result = std::from_chars (str, end_ptr, num);
     231                 :        5161 :     if (result.ec != std::errc())
     232                 :           6 :         return {};
     233                 :             : 
     234                 :        5155 :     if (result.ptr == end_ptr)
     235                 :           1 :         return gnc_numeric_create (num, 1);
     236                 :             : 
     237                 :        5154 :     if (*result.ptr != '/')
     238                 :          20 :         return {};
     239                 :             : 
     240                 :        5134 :     result = std::from_chars (result.ptr + 1, end_ptr, denom);
     241                 :        5134 :     if (result.ec != std::errc() || result.ptr != end_ptr || denom <= 0)
     242                 :           0 :         return {};
     243                 :             : 
     244                 :        5134 :     return gnc_numeric_create (num, denom);
     245                 :             : }
     246                 :             : 
     247                 :          19 : GncNumeric::GncNumeric(const std::string &str, bool autoround) {
     248                 :          27 :     static const std::string begin("^[^-.0-9]*");
     249                 :          27 :     static const std::string end("[^0-9]*$");
     250                 :          27 :     static const std::string begin_group("(?:");
     251                 :          27 :     static const std::string end_group(")");
     252                 :          27 :     static const std::string or_op("|");
     253                 :          27 :     static const std::string maybe_sign ("(-?)");
     254                 :          27 :     static const std::string opt_signed_int("(-?[0-9]*)");
     255                 :          27 :     static const std::string opt_signed_separated_int("(-?[0-9]{1,3})");
     256                 :          27 :     static const std::string unsigned_int("([0-9]+)");
     257                 :          27 :     static const std::string eu_separated_int("(?:[[:space:]'.]([0-9]{3}))?");
     258                 :          27 :     static const std::string en_separated_int("(?:\\,([0-9]{3}))?");
     259                 :          27 :     static const std::string eu_decimal_part("(?:\\,([0-9]+))?");
     260                 :          27 :     static const std::string en_decimal_part("(?:\\.([0-9]+))?");
     261                 :          27 :     static const std::string hex_frag("(0[xX][A-Fa-f0-9]+)");
     262                 :          27 :     static const std::string slash("[ \\t]*/[ \\t]*");
     263                 :          27 :     static const std::string whitespace("[ \\t]+");
     264                 :          19 :     static const std::string eu_sep_decimal(begin_group + opt_signed_separated_int + eu_separated_int + eu_separated_int + eu_separated_int + eu_separated_int + eu_decimal_part + end_group);
     265                 :          19 :     static const std::string en_sep_decimal(begin_group + opt_signed_separated_int + en_separated_int + en_separated_int + en_separated_int + en_separated_int + en_decimal_part + end_group);
     266                 :             :     /* The llvm standard C++ library refused to recognize the - in the
     267                 :             :      * opt_signed_int pattern with the default ECMAScript syntax so we use the
     268                 :             :      * awk syntax.
     269                 :             :      */
     270                 :          19 :     static const regex numeral(begin + opt_signed_int + end);
     271                 :          19 :     static const regex hex(begin + hex_frag + end);
     272                 :          19 :     static const regex numeral_rational(begin + opt_signed_int + slash + unsigned_int + end);
     273                 :          19 :     static const regex integer_and_fraction(begin + maybe_sign + unsigned_int + whitespace + unsigned_int + slash + unsigned_int + end);
     274                 :          19 :     static const regex hex_rational(begin + hex_frag + slash + hex_frag + end);
     275                 :          19 :     static const regex hex_over_num(begin + hex_frag + slash + unsigned_int + end);
     276                 :          19 :     static const regex num_over_hex(begin + opt_signed_int + slash + hex_frag + end);
     277                 :          19 :     static const regex decimal(begin + opt_signed_int + "[.,]" + unsigned_int + end);
     278                 :             :     static const u32regex sep_decimal =
     279                 :          19 :         boost::make_u32regex(begin + begin_group + eu_sep_decimal + or_op + en_sep_decimal + end_group + end);
     280                 :          19 :     static const regex scientific("(?:(-?[0-9]+[.,]?)|(-?[0-9]*)[.,]([0-9]+))[Ee](-?[0-9]+)");
     281                 :          19 :     static const regex has_hex_prefix(".*0[xX]$");
     282                 :          57 :     smatch m, x;
     283                 :             :     /* The order of testing the regexes is from the more restrictve to the less
     284                 :             :      * restrictive, as less-restrictive ones will match  patterns that would also
     285                 :             :      * match the more-restrictive and so invoke the wrong construction.
     286                 :             :      */
     287                 :          19 :     if (str.empty())
     288                 :             :         throw std::invalid_argument(
     289                 :           1 :             "Can't construct a GncNumeric from an empty string.");
     290                 :          18 :     if (auto res = fast_numeral_rational (str.c_str()))
     291                 :             :     {
     292                 :           0 :         m_num = res->num;
     293                 :           0 :         m_den = res->denom;
     294                 :           0 :         return;
     295                 :             :     }
     296                 :          18 :     if (regex_search(str, m, hex_rational))
     297                 :             :     {
     298                 :           0 :         GncNumeric n(stoll(m[1].str(), nullptr, 16),
     299                 :           0 :                      stoll(m[2].str(), nullptr, 16));
     300                 :             : 
     301                 :           0 :         m_num = n.num();
     302                 :           0 :         m_den = n.denom();
     303                 :           0 :         return;
     304                 :             :     }
     305                 :          18 :     if (regex_search(str, m, hex_over_num))
     306                 :             :     {
     307                 :           0 :         GncNumeric n(stoll(m[1].str(), nullptr, 16), stoll(m[2].str()));
     308                 :           0 :         m_num = n.num();
     309                 :           0 :         m_den = n.denom();
     310                 :           0 :         return;
     311                 :             :     }
     312                 :          18 :     if (regex_search(str, m, num_over_hex))
     313                 :             :     {
     314                 :           0 :         GncNumeric n(stoll(m[1].str()), stoll(m[2].str(), nullptr, 16));
     315                 :           0 :         m_num = n.num();
     316                 :           0 :         m_den = n.denom();
     317                 :           0 :         return;
     318                 :             :     }
     319                 :          18 :     if (regex_search(str, m, integer_and_fraction))
     320                 :             :     {
     321                 :           2 :         GncNumeric n(stoll(m[3].str()), stoll(m[4].str()));
     322                 :           2 :         n += stoll(m[2].str());
     323                 :           2 :         m_num = m[1].str().empty() ? n.num() : -n.num();
     324                 :           2 :         m_den = n.denom();
     325                 :           2 :         return;
     326                 :             :     }
     327                 :          16 :     if (regex_search(str, m, numeral_rational))
     328                 :             :     {
     329                 :           0 :         GncNumeric n(stoll(m[1].str()), stoll(m[2].str()));
     330                 :           0 :         m_num = n.num();
     331                 :           0 :         m_den = n.denom();
     332                 :           0 :         return;
     333                 :             :     }
     334                 :          16 :     if (regex_search(str, m, scientific) && ! regex_match(m.prefix().str(), x,  has_hex_prefix))
     335                 :             :     {
     336                 :           0 :         auto [num, denom] =
     337                 :           0 :             reduce_number_pair(numeric_from_scientific_match(m),
     338                 :             :                                    str, autoround);
     339                 :           0 :         m_num = num;
     340                 :           0 :         m_den = denom;
     341                 :           0 :         return;
     342                 :             :     }
     343                 :          16 :     if (regex_search(str, m, decimal))
     344                 :             :     {
     345                 :          14 :         std::string integer{m[1].matched ? m[1].str() : ""};
     346                 :          14 :         std::string decimal{m[2].matched ? m[2].str() : ""};
     347                 :          14 :         auto [num, denom] = reduce_number_pair(numeric_from_decimal_match(integer, decimal), str, autoround);
     348                 :          14 :         m_num = num;
     349                 :          14 :         m_den = denom;
     350                 :          14 :         return;
     351                 :          14 :     }
     352                 :           2 :     if (u32regex_search(str, m, sep_decimal))
     353                 :             :     {
     354                 :             :         /* There's a bit of magic here because of the complexity of
     355                 :             :          * the regex. It supports two formats, one for locales that
     356                 :             :          * use space, apostrophe, or dot for thousands separator and
     357                 :             :          * comma for decimal separator and the other for locales that
     358                 :             :          * use comma for thousands and dot for decimal. For each
     359                 :             :          * format there are 5 captures for thousands-groups (allowing
     360                 :             :          * up to 10^16 - 1) and one for decimal, hence the loops from
     361                 :             :          * 1 - 5 and 7 - 11 with the decimal being either capture 6 or
     362                 :             :          * capture 12.
     363                 :             :          */
     364                 :           0 :         std::string integer(""), decimal("");
     365                 :           0 :         for (auto i{1}; i < 6; ++i)
     366                 :           0 :             if (m[i].matched)
     367                 :           0 :                 integer += m[i].str();
     368                 :           0 :         if (m[6].matched)
     369                 :           0 :             decimal += m[6].str();
     370                 :           0 :         if (integer.empty() && decimal.empty())
     371                 :             :         {
     372                 :           0 :             for (auto i{7}; i <12; ++i)
     373                 :           0 :                 if (m[i].matched)
     374                 :           0 :                 integer += m[i].str();
     375                 :           0 :         if (m[12].matched)
     376                 :           0 :             decimal += m[12].str();
     377                 :             :         }
     378                 :           0 :         auto [num, denom] =
     379                 :           0 :             reduce_number_pair(numeric_from_decimal_match(integer, decimal),
     380                 :             :                                str, autoround);
     381                 :           0 :         m_num = num;
     382                 :           0 :         m_den = denom;
     383                 :           0 :         return;
     384                 :           0 :     }
     385                 :           2 :     if (regex_search(str, m, hex))
     386                 :             :     {
     387                 :           0 :         GncNumeric n(stoll(m[1].str(), nullptr, 16), INT64_C(1));
     388                 :           0 :         m_num = n.num();
     389                 :           0 :         m_den = n.denom();
     390                 :           0 :         return;
     391                 :             :     }
     392                 :           2 :     if (regex_search(str, m, numeral))
     393                 :             :     {
     394                 :           2 :         GncNumeric n(stoll(m[1].str()), INT64_C(1));
     395                 :           0 :         m_num = n.num();
     396                 :           0 :         m_den = n.denom();
     397                 :           0 :         return;
     398                 :             :     }
     399                 :           1 :     std::ostringstream errmsg;
     400                 :           1 :     errmsg << "String " << str << " contains no recognizable numeric value.";
     401                 :           1 :     throw std::invalid_argument(errmsg.str());
     402                 :          23 : }
     403                 :             : 
     404                 :      550418 : GncNumeric::operator gnc_numeric() const noexcept
     405                 :             : {
     406                 :      550418 :     return {m_num, m_den};
     407                 :             : }
     408                 :             : 
     409                 :           0 : GncNumeric::operator double() const noexcept
     410                 :             : {
     411                 :           0 :     return static_cast<double>(m_num) / static_cast<double>(m_den);
     412                 :             : }
     413                 :             : 
     414                 :             : GncNumeric
     415                 :       70586 : GncNumeric::operator-() const noexcept
     416                 :             : {
     417                 :       70586 :     GncNumeric b(*this);
     418                 :       70586 :     b.m_num = - b.m_num;
     419                 :       70586 :     return b;
     420                 :             : }
     421                 :             : 
     422                 :             : GncNumeric
     423                 :         708 : GncNumeric::inv() const noexcept
     424                 :             : {
     425                 :         708 :     if (m_num == 0)
     426                 :           0 :         return *this;
     427                 :         708 :     if (m_num < 0)
     428                 :           0 :         return GncNumeric(-m_den, -m_num);
     429                 :         708 :     return GncNumeric(m_den, m_num);
     430                 :             : }
     431                 :             : 
     432                 :             : GncNumeric
     433                 :           0 : GncNumeric::abs() const noexcept
     434                 :             : {
     435                 :           0 :     if (m_num < 0)
     436                 :           0 :         return -*this;
     437                 :           0 :     return *this;
     438                 :             : }
     439                 :             : 
     440                 :             : GncNumeric
     441                 :        4394 : GncNumeric::reduce() const noexcept
     442                 :             : {
     443                 :        4394 :     return static_cast<GncNumeric>(GncRational(*this).reduce());
     444                 :             : }
     445                 :             : 
     446                 :             : GncNumeric::round_param
     447                 :      514282 : GncNumeric::prepare_conversion(int64_t new_denom) const
     448                 :             : {
     449                 :      514282 :     if (new_denom == m_den || new_denom == GNC_DENOM_AUTO)
     450                 :      422494 :         return {m_num, m_den, 0};
     451                 :       91788 :     GncRational conversion(new_denom, m_den);
     452                 :       91788 :     auto red_conv = conversion.reduce();
     453                 :       91788 :     GncInt128 old_num(m_num);
     454                 :       91788 :     auto new_num = old_num * red_conv.num();
     455                 :       91788 :     auto rem = new_num % red_conv.denom();
     456                 :       91788 :     new_num /= red_conv.denom();
     457                 :       91788 :     if (new_num.isBig())
     458                 :             :     {
     459                 :          15 :         GncRational rr(new_num, new_denom);
     460                 :          15 :         GncNumeric nn(rr);
     461                 :          15 :         rr = rr.convert<RoundType::truncate>(new_denom);
     462                 :          15 :         return {static_cast<int64_t>(rr.num()), new_denom, 0};
     463                 :             :     }
     464                 :       91773 :     return {static_cast<int64_t>(new_num),
     465                 :       91773 :             static_cast<int64_t>(red_conv.denom()), static_cast<int64_t>(rem)};
     466                 :             : }
     467                 :             : 
     468                 :             : int64_t
     469                 :          33 : GncNumeric::sigfigs_denom(unsigned figs) const noexcept
     470                 :             : {
     471                 :          33 :     if (m_num == 0)
     472                 :           4 :         return 1;
     473                 :             : 
     474                 :          29 :     int64_t num_abs{std::abs(m_num)};
     475                 :          29 :     bool not_frac = num_abs > m_den;
     476                 :          29 :     int64_t val{ not_frac ? num_abs / m_den : m_den / num_abs };
     477                 :          29 :     unsigned digits{};
     478                 :          44 :     while (val >= 10)
     479                 :             :     {
     480                 :          15 :         ++digits;
     481                 :          15 :         val /= 10;
     482                 :             :     }
     483                 :          29 :     return not_frac ? 
     484                 :          23 :             powten(digits < figs ? figs - digits - 1 : 0) : 
     485                 :          29 :             powten(figs + digits);
     486                 :             : }
     487                 :             : 
     488                 :             : std::string
     489                 :           0 : GncNumeric::to_string() const noexcept
     490                 :             : {
     491                 :           0 :     std::ostringstream out;
     492                 :           0 :     out << *this;
     493                 :           0 :     return out.str();
     494                 :           0 : }
     495                 :             : 
     496                 :             : bool
     497                 :       32397 : GncNumeric::is_decimal() const noexcept
     498                 :             : {
     499                 :       65941 :     for (unsigned pwr = 0; pwr < max_leg_digits && m_den >= pten[pwr]; ++pwr)
     500                 :             :     {
     501                 :       65166 :         if (m_den == pten[pwr])
     502                 :       31330 :             return true;
     503                 :       33836 :         if (m_den % pten[pwr])
     504                 :         292 :             return false;
     505                 :             :     }
     506                 :         775 :     return false;
     507                 :             : }
     508                 :             : 
     509                 :             : GncNumeric
     510                 :       32117 : GncNumeric::to_decimal(unsigned int max_places) const
     511                 :             : {
     512                 :       32117 :     if (max_places > max_leg_digits)
     513                 :           0 :         max_places = max_leg_digits;
     514                 :             : 
     515                 :       32117 :     if (m_num == 0)
     516                 :           0 :         return GncNumeric();
     517                 :             : 
     518                 :       32117 :     if (is_decimal())
     519                 :             :     {
     520                 :       31050 :         if (m_num == 0 || m_den < powten(max_places))
     521                 :       31050 :             return *this; // Nothing to do.
     522                 :             :         /* See if we can reduce m_num to fit in max_places */
     523                 :           0 :         auto excess = m_den / powten(max_places);
     524                 :           0 :         if (m_num % excess)
     525                 :             :         {
     526                 :           0 :             std::ostringstream msg;
     527                 :           0 :             msg << "GncNumeric " << *this
     528                 :           0 :                 << " could not be represented in " << max_places
     529                 :           0 :                 << " decimal places without rounding.\n";
     530                 :           0 :             throw std::range_error(msg.str());
     531                 :           0 :         }
     532                 :           0 :         return GncNumeric(m_num / excess, powten(max_places));
     533                 :             :     }
     534                 :        1067 :     GncRational rr(*this);
     535                 :        1067 :     rr = rr.convert<RoundType::never>(powten(max_places)); //May throw
     536                 :             :     /* rr might have gotten reduced a bit too much; if so, put it back: */
     537                 :         981 :     unsigned int pwr{1};
     538                 :       18639 :     for (; pwr <= max_places && !(rr.denom() % powten(pwr)); ++pwr);
     539                 :         981 :     auto reduce_to = powten(pwr);
     540                 :         981 :     GncInt128 rr_num(rr.num()), rr_den(rr.denom());
     541                 :         981 :     if (rr_den % reduce_to)
     542                 :             :     {
     543                 :           0 :         auto factor(reduce_to / rr.denom());
     544                 :           0 :         rr_num *= factor;
     545                 :           0 :         rr_den *= factor;
     546                 :             :     }
     547                 :       16870 :     while (!rr_num.isZero() && rr_num > 9 && rr_den > 9 && rr_num % 10 == 0)
     548                 :             :     {
     549                 :       15889 :         rr_num /= 10;
     550                 :       15889 :         rr_den /= 10;
     551                 :             :     }
     552                 :             :     try
     553                 :             :     {
     554                 :             :         /* Construct from the parts to avoid the GncRational constructor's
     555                 :             :          * automatic rounding.
     556                 :             :          */
     557                 :         981 :         return {static_cast<int64_t>(rr_num), static_cast<int64_t>(rr_den)};
     558                 :             :     }
     559                 :           0 :     catch (const std::invalid_argument& err)
     560                 :             :     {
     561                 :           0 :         std::ostringstream msg;
     562                 :           0 :         msg << "GncNumeric " << *this
     563                 :           0 :             << " could not be represented as a decimal without rounding.\n";
     564                 :           0 :         throw std::range_error(msg.str());
     565                 :           0 :     }
     566                 :           0 :     catch (const std::overflow_error& err)
     567                 :             :     {
     568                 :           0 :         std::ostringstream msg;
     569                 :           0 :         msg << "GncNumeric " << *this
     570                 :           0 :             << " overflows when attempting to convert it to decimal.\n";
     571                 :           0 :         throw std::range_error(msg.str());
     572                 :           0 :     }
     573                 :           0 :     catch (const std::underflow_error& err)
     574                 :             :     {
     575                 :           0 :         std::ostringstream msg;
     576                 :           0 :         msg << "GncNumeric " << *this
     577                 :           0 :             << " underflows when attempting to convert it to decimal.\n";
     578                 :           0 :         throw std::range_error(msg.str());
     579                 :           0 :     }
     580                 :             : }
     581                 :             : 
     582                 :             : void
     583                 :         188 : GncNumeric::operator+=(GncNumeric b)
     584                 :             : {
     585                 :         188 :     *this = *this + b;
     586                 :         188 : }
     587                 :             : 
     588                 :             : void
     589                 :           0 : GncNumeric::operator-=(GncNumeric b)
     590                 :             : {
     591                 :           0 :     *this = *this - b;
     592                 :           0 : }
     593                 :             : 
     594                 :             : void
     595                 :           0 : GncNumeric::operator*=(GncNumeric b)
     596                 :             : {
     597                 :           0 :     *this = *this * b;
     598                 :           0 : }
     599                 :             : 
     600                 :             : void
     601                 :           0 : GncNumeric::operator/=(GncNumeric b)
     602                 :             : {
     603                 :           0 :     *this = *this / b;
     604                 :           0 : }
     605                 :             : 
     606                 :             : int
     607                 :        2678 : GncNumeric::cmp(GncNumeric b)
     608                 :             : {
     609                 :        2678 :     if (m_den == b.denom())
     610                 :             :     {
     611                 :          10 :         auto b_num = b.num();
     612                 :          10 :         return m_num < b_num ? -1 : b_num < m_num ? 1 : 0;
     613                 :             :     }
     614                 :        2668 :     GncRational an(*this), bn(b);
     615                 :        2668 :     return an.cmp(bn);
     616                 :             : }
     617                 :             : 
     618                 :             : GncNumeric
     619                 :      333452 : operator+(GncNumeric a, GncNumeric b)
     620                 :             : {
     621                 :      333452 :     if (a.num() == 0)
     622                 :       64707 :         return b;
     623                 :      268745 :     if (b.num() == 0)
     624                 :        8037 :         return a;
     625                 :      260708 :     GncRational ar(a), br(b);
     626                 :      260708 :     auto rr = ar + br;
     627                 :      260708 :     return static_cast<GncNumeric>(rr);
     628                 :             : }
     629                 :             : 
     630                 :             : GncNumeric
     631                 :       70586 : operator-(GncNumeric a, GncNumeric b)
     632                 :             : {
     633                 :       70586 :     return a + (-b);
     634                 :             : }
     635                 :             : 
     636                 :             : GncNumeric
     637                 :        4282 : operator*(GncNumeric a, GncNumeric b)
     638                 :             : {
     639                 :        4282 :     if (a.num() == 0 || b.num() == 0)
     640                 :             :     {
     641                 :        3189 :         GncNumeric retval;
     642                 :        3189 :         return retval;
     643                 :             :     }
     644                 :        1093 :     GncRational ar(a), br(b);
     645                 :        1093 :     auto rr = ar * br;
     646                 :        1093 :     return static_cast<GncNumeric>(rr);
     647                 :             : }
     648                 :             : 
     649                 :             : GncNumeric
     650                 :        1298 : operator/(GncNumeric a, GncNumeric b)
     651                 :             : {
     652                 :        1298 :     if (a.num() == 0)
     653                 :             :     {
     654                 :          10 :         GncNumeric retval;
     655                 :          10 :         return retval;
     656                 :             :     }
     657                 :        1288 :     if (b.num() == 0)
     658                 :           1 :         throw std::underflow_error("Attempt to divide by zero.");
     659                 :             : 
     660                 :        1287 :     GncRational ar(a), br(b);
     661                 :        1287 :     auto rr = ar / br;
     662                 :        1287 :     return static_cast<GncNumeric>(rr);
     663                 :             : }
     664                 :             : 
     665                 :             : template <typename T, typename I> T
     666                 :      519286 : convert(T num, I new_denom, int how)
     667                 :             : {
     668                 :      519286 :     auto rtype = static_cast<RoundType>(how & GNC_NUMERIC_RND_MASK);
     669                 :      519286 :     unsigned int figs = GNC_HOW_GET_SIGFIGS(how);
     670                 :             : 
     671                 :      519286 :     auto dtype = static_cast<DenomType>(how & GNC_NUMERIC_DENOM_MASK);
     672                 :      519286 :     bool sigfigs = dtype == DenomType::sigfigs;
     673                 :      519286 :     if (dtype == DenomType::reduce)
     674                 :         740 :         num = num.reduce();
     675                 :             : 
     676                 :      519286 :     switch (rtype)
     677                 :             :     {
     678                 :           1 :         case RoundType::floor:
     679                 :           1 :             if (sigfigs)
     680                 :           0 :                 return num.template convert_sigfigs<RoundType::floor>(figs);
     681                 :             :             else
     682                 :           1 :                 return num.template convert<RoundType::floor>(new_denom);
     683                 :           1 :         case RoundType::ceiling:
     684                 :           1 :             if (sigfigs)
     685                 :           0 :                 return num.template convert_sigfigs<RoundType::ceiling>(figs);
     686                 :             :             else
     687                 :           1 :                 return num.template convert<RoundType::ceiling>(new_denom);
     688                 :       65381 :         case RoundType::truncate:
     689                 :       65381 :             if (sigfigs)
     690                 :           0 :                 return num.template convert_sigfigs<RoundType::truncate>(figs);
     691                 :             :             else
     692                 :       65381 :                 return num.template convert<RoundType::truncate>(new_denom);
     693                 :           0 :         case RoundType::promote:
     694                 :           0 :             if (sigfigs)
     695                 :           0 :                 return num.template convert_sigfigs<RoundType::promote>(figs);
     696                 :             :             else
     697                 :           0 :                 return num.template convert<RoundType::promote>(new_denom);
     698                 :           0 :         case RoundType::half_down:
     699                 :           0 :             if (sigfigs)
     700                 :           0 :                 return num.template convert_sigfigs<RoundType::half_down>(figs);
     701                 :             :             else
     702                 :           0 :                 return num.template convert<RoundType::half_down>(new_denom);
     703                 :       42919 :         case RoundType::half_up:
     704                 :       42919 :             if (sigfigs)
     705                 :          25 :                 return num.template convert_sigfigs<RoundType::half_up>(figs);
     706                 :             :             else
     707                 :       42894 :                 return num.template convert<RoundType::half_up>(new_denom);
     708                 :       80661 :         case RoundType::bankers:
     709                 :       80661 :             if (sigfigs)
     710                 :           8 :                 return num.template convert_sigfigs<RoundType::bankers>(figs);
     711                 :             :             else
     712                 :       80653 :                 return num.template convert<RoundType::bankers>(new_denom);
     713                 :      324846 :         case RoundType::never:
     714                 :      324846 :             if (sigfigs)
     715                 :           0 :                 return num.template convert_sigfigs<RoundType::never>(figs);
     716                 :             :             else
     717                 :      324846 :                 return num.template convert<RoundType::never>(new_denom);
     718                 :        5477 :         default:
     719                 :             :             /* round-truncate just returns the numerator unchanged. The old
     720                 :             :              * gnc-numeric convert had no "default" behavior at rounding that
     721                 :             :              * had the same result, but we need to make it explicit here to
     722                 :             :              * run the rest of the conversion code.
     723                 :             :              */
     724                 :        5477 :             if (sigfigs)
     725                 :           0 :                 return num.template convert_sigfigs<RoundType::truncate>(figs);
     726                 :             :             else
     727                 :        5477 :                 return num.template convert<RoundType::truncate>(new_denom);
     728                 :             : 
     729                 :             :     }
     730                 :             : }
     731                 :             : 
     732                 :             : /* =============================================================== */
     733                 :             : /* This function is small, simple, and used everywhere below,
     734                 :             :  * lets try to inline it.
     735                 :             :  */
     736                 :             : GNCNumericErrorCode
     737                 :     1782960 : gnc_numeric_check(gnc_numeric in)
     738                 :             : {
     739                 :     1782960 :     if (G_LIKELY(in.denom != 0))
     740                 :             :     {
     741                 :     1782789 :         return GNC_ERROR_OK;
     742                 :             :     }
     743                 :         171 :     else if (in.num)
     744                 :             :     {
     745                 :         130 :         if ((0 < in.num) || (-4 > in.num))
     746                 :             :         {
     747                 :           6 :             in.num = (gint64) GNC_ERROR_OVERFLOW;
     748                 :             :         }
     749                 :         130 :         return (GNCNumericErrorCode) in.num;
     750                 :             :     }
     751                 :             :     else
     752                 :             :     {
     753                 :          41 :         return GNC_ERROR_ARG;
     754                 :             :     }
     755                 :             : }
     756                 :             : 
     757                 :             : 
     758                 :             : /* *******************************************************************
     759                 :             :  *  gnc_numeric_zero_p
     760                 :             :  ********************************************************************/
     761                 :             : 
     762                 :             : gboolean
     763                 :      187279 : gnc_numeric_zero_p(gnc_numeric a)
     764                 :             : {
     765                 :      187279 :     if (gnc_numeric_check(a))
     766                 :             :     {
     767                 :           1 :         return 0;
     768                 :             :     }
     769                 :             :     else
     770                 :             :     {
     771                 :      187278 :         if ((a.num == 0) && (a.denom != 0))
     772                 :             :         {
     773                 :      127646 :             return 1;
     774                 :             :         }
     775                 :             :         else
     776                 :             :         {
     777                 :       59632 :             return 0;
     778                 :             :         }
     779                 :             :     }
     780                 :             : }
     781                 :             : 
     782                 :             : /* *******************************************************************
     783                 :             :  *  gnc_numeric_negative_p
     784                 :             :  ********************************************************************/
     785                 :             : 
     786                 :             : gboolean
     787                 :      214206 : gnc_numeric_negative_p(gnc_numeric a)
     788                 :             : {
     789                 :      214206 :     if (gnc_numeric_check(a))
     790                 :             :     {
     791                 :           0 :         return 0;
     792                 :             :     }
     793                 :             :     else
     794                 :             :     {
     795                 :      214206 :         if ((a.num < 0) && (a.denom != 0))
     796                 :             :         {
     797                 :       41198 :             return 1;
     798                 :             :         }
     799                 :             :         else
     800                 :             :         {
     801                 :      173008 :             return 0;
     802                 :             :         }
     803                 :             :     }
     804                 :             : }
     805                 :             : 
     806                 :             : /* *******************************************************************
     807                 :             :  *  gnc_numeric_positive_p
     808                 :             :  ********************************************************************/
     809                 :             : 
     810                 :             : gboolean
     811                 :        2220 : gnc_numeric_positive_p(gnc_numeric a)
     812                 :             : {
     813                 :        2220 :     if (gnc_numeric_check(a))
     814                 :             :     {
     815                 :           0 :         return 0;
     816                 :             :     }
     817                 :             :     else
     818                 :             :     {
     819                 :        2220 :         if ((a.num > 0) && (a.denom != 0))
     820                 :             :         {
     821                 :        1352 :             return 1;
     822                 :             :         }
     823                 :             :         else
     824                 :             :         {
     825                 :         868 :             return 0;
     826                 :             :         }
     827                 :             :     }
     828                 :             : }
     829                 :             : 
     830                 :             : 
     831                 :             : /* *******************************************************************
     832                 :             :  *  gnc_numeric_compare
     833                 :             :  *  returns 1 if a>b, -1 if b>a, 0 if a == b
     834                 :             :  ********************************************************************/
     835                 :             : 
     836                 :             : int
     837                 :       24043 : gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
     838                 :             : {
     839                 :       24043 :     if (gnc_numeric_check(a) || gnc_numeric_check(b))
     840                 :             :     {
     841                 :           0 :         return 0;
     842                 :             :     }
     843                 :             : 
     844                 :       24043 :     if (a.denom == b.denom)
     845                 :             :     {
     846                 :       21375 :         if (a.num == b.num) return 0;
     847                 :       10339 :         if (a.num > b.num) return 1;
     848                 :        4593 :         return -1;
     849                 :             :     }
     850                 :             : 
     851                 :        2668 :     GncNumeric an (a), bn (b);
     852                 :             : 
     853                 :        2668 :     return an.cmp(bn);
     854                 :             : }
     855                 :             : 
     856                 :             : 
     857                 :             : /* *******************************************************************
     858                 :             :  *  gnc_numeric_eq
     859                 :             :  ********************************************************************/
     860                 :             : 
     861                 :             : gboolean
     862                 :        3397 : gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
     863                 :             : {
     864                 :        3397 :     return ((a.num == b.num) && (a.denom == b.denom));
     865                 :             : }
     866                 :             : 
     867                 :             : 
     868                 :             : /* *******************************************************************
     869                 :             :  *  gnc_numeric_equal
     870                 :             :  ********************************************************************/
     871                 :             : 
     872                 :             : gboolean
     873                 :       11627 : gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
     874                 :             : {
     875                 :       11627 :     if (gnc_numeric_check(a))
     876                 :             :     {
     877                 :             :         /* a is not a valid number, check b */
     878                 :           0 :         if (gnc_numeric_check(b))
     879                 :             :             /* Both invalid, consider them equal */
     880                 :           0 :             return TRUE;
     881                 :             :         else
     882                 :             :             /* a invalid, b valid */
     883                 :           0 :             return FALSE;
     884                 :             :     }
     885                 :       11627 :     if (gnc_numeric_check(b))
     886                 :             :         /* a valid, b invalid */
     887                 :           0 :         return FALSE;
     888                 :             : 
     889                 :       11627 :     return gnc_numeric_compare (a, b) == 0;
     890                 :             : }
     891                 :             : 
     892                 :             : 
     893                 :             : /* *******************************************************************
     894                 :             :  *  gnc_numeric_same
     895                 :             :  *  would a and b be equal() if they were both converted to the same
     896                 :             :  *  denominator?
     897                 :             :  ********************************************************************/
     898                 :             : 
     899                 :             : int
     900                 :        5005 : gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom,
     901                 :             :                  gint how)
     902                 :             : {
     903                 :             :     gnc_numeric aconv, bconv;
     904                 :             : 
     905                 :        5005 :     aconv = gnc_numeric_convert(a, denom, how);
     906                 :        5005 :     bconv = gnc_numeric_convert(b, denom, how);
     907                 :             : 
     908                 :       10010 :     return(gnc_numeric_equal(aconv, bconv));
     909                 :             : }
     910                 :             : 
     911                 :             : static int64_t
     912                 :      350401 : denom_lcd(gnc_numeric a, gnc_numeric b, int64_t denom, int how)
     913                 :             : {
     914                 :      350401 :     if (denom == GNC_DENOM_AUTO &&
     915                 :      341615 :         (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)
     916                 :             :     {
     917                 :         734 :         GncInt128 ad(a.denom), bd(b.denom);
     918                 :         734 :         denom = static_cast<int64_t>(ad.lcm(bd));
     919                 :             :     }
     920                 :      350401 :     return denom;
     921                 :             : }
     922                 :             : 
     923                 :             : /* *******************************************************************
     924                 :             :  *  gnc_numeric_add
     925                 :             :  ********************************************************************/
     926                 :             : 
     927                 :             : gnc_numeric
     928                 :      269737 : gnc_numeric_add(gnc_numeric a, gnc_numeric b,
     929                 :             :                 gint64 denom, gint how)
     930                 :             : {
     931                 :      269737 :     if (gnc_numeric_check(a) || gnc_numeric_check(b))
     932                 :             :     {
     933                 :           3 :         return gnc_numeric_error(GNC_ERROR_ARG);
     934                 :             :     }
     935                 :             :     try
     936                 :             :     {
     937                 :      269734 :         denom = denom_lcd(a, b, denom, how);
     938                 :      269734 :         if ((how & GNC_NUMERIC_DENOM_MASK) != GNC_HOW_DENOM_EXACT)
     939                 :             :         {
     940                 :      262678 :             GncNumeric an (a), bn (b);
     941                 :      262678 :             GncNumeric sum = an + bn;
     942                 :      262678 :             return static_cast<gnc_numeric>(convert(sum, denom, how));
     943                 :             :         }
     944                 :        7056 :         GncRational ar(a), br(b);
     945                 :        7056 :         auto sum = ar + br;
     946                 :        7056 :         if (denom == GNC_DENOM_AUTO &&
     947                 :        6482 :             (how & GNC_NUMERIC_RND_MASK) != GNC_HOW_RND_NEVER)
     948                 :        6482 :             return static_cast<gnc_numeric>(sum.round_to_numeric());
     949                 :         574 :         sum = convert(sum, denom, how);
     950                 :         574 :         if (sum.is_big() || !sum.valid())
     951                 :           0 :             return gnc_numeric_error(GNC_ERROR_OVERFLOW);
     952                 :         574 :         return static_cast<gnc_numeric>(sum);
     953                 :             :     }
     954                 :           0 :     catch (const std::overflow_error& err)
     955                 :             :     {
     956                 :           0 :         PWARN("%s", err.what());
     957                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
     958                 :           0 :     }
     959                 :           0 :     catch (const std::invalid_argument& err)
     960                 :             :     {
     961                 :           0 :         PWARN("%s", err.what());
     962                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
     963                 :           0 :     }
     964                 :           0 :     catch (const std::underflow_error& err)
     965                 :             :     {
     966                 :           0 :         PWARN("%s", err.what());
     967                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
     968                 :           0 :     }
     969                 :           0 :     catch (const std::domain_error& err)
     970                 :             :     {
     971                 :           0 :         PWARN("%s", err.what());
     972                 :           0 :         return gnc_numeric_error(GNC_ERROR_REMAINDER);
     973                 :           0 :     }
     974                 :             : }
     975                 :             : 
     976                 :             : /* *******************************************************************
     977                 :             :  *  gnc_numeric_sub
     978                 :             :  ********************************************************************/
     979                 :             : 
     980                 :             : gnc_numeric
     981                 :       70593 : gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
     982                 :             :                 gint64 denom, gint how)
     983                 :             : {
     984                 :       70593 :     if (gnc_numeric_check(a) || gnc_numeric_check(b))
     985                 :             :     {
     986                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
     987                 :             :     }
     988                 :             :     try
     989                 :             :     {
     990                 :       70593 :         denom = denom_lcd(a, b, denom, how);
     991                 :       70593 :         if ((how & GNC_NUMERIC_DENOM_MASK) != GNC_HOW_DENOM_EXACT)
     992                 :             :         {
     993                 :       70586 :             GncNumeric an (a), bn (b);
     994                 :       70586 :             auto sum = an - bn;
     995                 :       70586 :             return static_cast<gnc_numeric>(convert(sum, denom, how));
     996                 :             :         }
     997                 :           7 :         GncRational ar(a), br(b);
     998                 :           7 :         auto sum = ar - br;
     999                 :           7 :         if (denom == GNC_DENOM_AUTO &&
    1000                 :           7 :             (how & GNC_NUMERIC_RND_MASK) != GNC_HOW_RND_NEVER)
    1001                 :           7 :             return static_cast<gnc_numeric>(sum.round_to_numeric());
    1002                 :           0 :         sum = convert(sum, denom, how);
    1003                 :           0 :         if (sum.is_big() || !sum.valid())
    1004                 :           0 :             return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1005                 :           0 :         return static_cast<gnc_numeric>(sum);
    1006                 :             :     }
    1007                 :           0 :     catch (const std::overflow_error& err)
    1008                 :             :     {
    1009                 :           0 :         PWARN("%s", err.what());
    1010                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1011                 :           0 :     }
    1012                 :           0 :     catch (const std::invalid_argument& err)
    1013                 :             :     {
    1014                 :           0 :         PWARN("%s", err.what());
    1015                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1016                 :           0 :     }
    1017                 :           0 :     catch (const std::underflow_error& err)
    1018                 :             :     {
    1019                 :           0 :         PWARN("%s", err.what());
    1020                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1021                 :           0 :     }
    1022                 :           0 :     catch (const std::domain_error& err)
    1023                 :             :     {
    1024                 :           0 :         PWARN("%s", err.what());
    1025                 :           0 :         return gnc_numeric_error(GNC_ERROR_REMAINDER);
    1026                 :           0 :     }
    1027                 :             : }
    1028                 :             : 
    1029                 :             : /* *******************************************************************
    1030                 :             :  *  gnc_numeric_mul
    1031                 :             :  ********************************************************************/
    1032                 :             : 
    1033                 :             : gnc_numeric
    1034                 :        8293 : gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
    1035                 :             :                 gint64 denom, gint how)
    1036                 :             : {
    1037                 :        8293 :     if (gnc_numeric_check(a) || gnc_numeric_check(b))
    1038                 :             :     {
    1039                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1040                 :             :     }
    1041                 :             : 
    1042                 :             :     try
    1043                 :             :     {
    1044                 :        8293 :         denom = denom_lcd(a, b, denom, how);
    1045                 :        8293 :         if ((how & GNC_NUMERIC_DENOM_MASK) != GNC_HOW_DENOM_EXACT)
    1046                 :             :         {
    1047                 :        4282 :             GncNumeric an (a), bn (b);
    1048                 :        4282 :             auto prod = an * bn;
    1049                 :        4254 :             return static_cast<gnc_numeric>(convert(prod, denom, how));
    1050                 :             :         }
    1051                 :        4011 :         GncRational ar(a), br(b);
    1052                 :        4011 :         auto prod = ar * br;
    1053                 :        4011 :         if (denom == GNC_DENOM_AUTO &&
    1054                 :          24 :             (how & GNC_NUMERIC_RND_MASK) != GNC_HOW_RND_NEVER)
    1055                 :          16 :             return static_cast<gnc_numeric>(prod.round_to_numeric());
    1056                 :        3995 :         prod = convert(prod, denom, how);
    1057                 :        3995 :         if (prod.is_big() || !prod.valid())
    1058                 :           0 :             return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1059                 :        3995 :         return static_cast<gnc_numeric>(prod);
    1060                 :             :      }
    1061                 :          43 :     catch (const std::overflow_error& err)
    1062                 :             :     {
    1063                 :          43 :         PWARN("%s", err.what());
    1064                 :          43 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1065                 :          43 :     }
    1066                 :           0 :     catch (const std::invalid_argument& err)
    1067                 :             :     {
    1068                 :           0 :         PWARN("%s", err.what());
    1069                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1070                 :           0 :     }
    1071                 :           0 :     catch (const std::underflow_error& err)
    1072                 :             :     {
    1073                 :           0 :         PWARN("%s", err.what());
    1074                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1075                 :           0 :     }
    1076                 :           0 :     catch (const std::domain_error& err)
    1077                 :             :     {
    1078                 :           0 :         PWARN("%s", err.what());
    1079                 :           0 :         return gnc_numeric_error(GNC_ERROR_REMAINDER);
    1080                 :           0 :     }
    1081                 :             : }
    1082                 :             : 
    1083                 :             : 
    1084                 :             : /* *******************************************************************
    1085                 :             :  *  gnc_numeric_div
    1086                 :             :  ********************************************************************/
    1087                 :             : 
    1088                 :             : gnc_numeric
    1089                 :        1785 : gnc_numeric_div(gnc_numeric a, gnc_numeric b,
    1090                 :             :                 gint64 denom, gint how)
    1091                 :             : {
    1092                 :        1785 :     if (gnc_numeric_check(a) || gnc_numeric_check(b))
    1093                 :             :     {
    1094                 :           4 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1095                 :             :     }
    1096                 :             :     try
    1097                 :             :     {
    1098                 :        1781 :         denom = denom_lcd(a, b, denom, how);
    1099                 :        1781 :         if ((how & GNC_NUMERIC_DENOM_MASK) != GNC_HOW_DENOM_EXACT)
    1100                 :             :         {
    1101                 :        1298 :             GncNumeric an (a), bn (b);
    1102                 :        1298 :             auto quot = an / bn;
    1103                 :        1297 :             return static_cast<gnc_numeric>(convert(quot, denom, how));
    1104                 :             :         }
    1105                 :         483 :         GncRational ar(a), br(b);
    1106                 :         483 :         auto quot = ar / br;
    1107                 :         482 :         if (denom == GNC_DENOM_AUTO &&
    1108                 :         482 :             (how & GNC_NUMERIC_RND_MASK) != GNC_HOW_RND_NEVER)
    1109                 :          47 :             return static_cast<gnc_numeric>(quot.round_to_numeric());
    1110                 :         435 :         quot =  static_cast<gnc_numeric>(convert(quot, denom, how));
    1111                 :         435 :         if (quot.is_big() || !quot.valid())
    1112                 :           0 :             return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1113                 :         435 :         return static_cast<gnc_numeric>(quot);
    1114                 :             :     }
    1115                 :           2 :     catch (const std::overflow_error& err)
    1116                 :             :     {
    1117                 :           0 :         PWARN("%s", err.what());
    1118                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1119                 :           0 :     }
    1120                 :           0 :     catch (const std::invalid_argument& err)
    1121                 :             :     {
    1122                 :           0 :         PWARN("%s", err.what());
    1123                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1124                 :           0 :     }
    1125                 :           2 :     catch (const std::underflow_error& err) //Divide by zero
    1126                 :             :     {
    1127                 :           2 :         PWARN("%s", err.what());
    1128                 :           2 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1129                 :           2 :     }
    1130                 :           0 :     catch (const std::domain_error& err)
    1131                 :             :     {
    1132                 :           0 :         PWARN("%s", err.what());
    1133                 :           0 :         return gnc_numeric_error(GNC_ERROR_REMAINDER);
    1134                 :           0 :     }
    1135                 :             : }
    1136                 :             : 
    1137                 :             : /* *******************************************************************
    1138                 :             :  *  gnc_numeric_neg
    1139                 :             :  *  negate the argument
    1140                 :             :  ********************************************************************/
    1141                 :             : 
    1142                 :             : gnc_numeric
    1143                 :        2054 : gnc_numeric_neg(gnc_numeric a)
    1144                 :             : {
    1145                 :        2054 :     if (gnc_numeric_check(a))
    1146                 :             :     {
    1147                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1148                 :             :     }
    1149                 :        2054 :     return gnc_numeric_create(- a.num, a.denom);
    1150                 :             : }
    1151                 :             : 
    1152                 :             : /* *******************************************************************
    1153                 :             :  *  gnc_numeric_abs
    1154                 :             :  *  return the absolute value of the argument
    1155                 :             :  ********************************************************************/
    1156                 :             : 
    1157                 :             : gnc_numeric
    1158                 :       66865 : gnc_numeric_abs(gnc_numeric a)
    1159                 :             : {
    1160                 :       66865 :     if (gnc_numeric_check(a))
    1161                 :             :     {
    1162                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1163                 :             :     }
    1164                 :       66865 :     return gnc_numeric_create(ABS(a.num), a.denom);
    1165                 :             : }
    1166                 :             : 
    1167                 :             : 
    1168                 :             : /* *******************************************************************
    1169                 :             :  *  gnc_numeric_convert
    1170                 :             :  ********************************************************************/
    1171                 :             : 
    1172                 :             : gnc_numeric
    1173                 :      175105 : gnc_numeric_convert(gnc_numeric in, int64_t denom, int how)
    1174                 :             : {
    1175                 :      175105 :     if (gnc_numeric_check(in))
    1176                 :           0 :         return in;
    1177                 :             :     try
    1178                 :             :     {
    1179                 :      175105 :         return convert(GncNumeric(in), denom, how);
    1180                 :             :     }
    1181                 :           0 :     catch (const std::invalid_argument& err)
    1182                 :             :     {
    1183                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1184                 :           0 :     }
    1185                 :           0 :     catch (const std::overflow_error& err)
    1186                 :             :     {
    1187                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1188                 :           0 :     }
    1189                 :           0 :     catch (const std::underflow_error& err)
    1190                 :             :     {
    1191                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1192                 :           0 :     }
    1193                 :           0 :     catch (const std::domain_error& err)
    1194                 :             :     {
    1195                 :           0 :         return gnc_numeric_error(GNC_ERROR_REMAINDER);
    1196                 :           0 :     }
    1197                 :             : }
    1198                 :             : 
    1199                 :             : 
    1200                 :             : /* *******************************************************************
    1201                 :             :  *  reduce a fraction by GCF elimination.  This is NOT done as a
    1202                 :             :  *  part of the arithmetic API unless GNC_HOW_DENOM_REDUCE is specified
    1203                 :             :  *  as the output denominator.
    1204                 :             :  ********************************************************************/
    1205                 :             : 
    1206                 :             : gnc_numeric
    1207                 :        3291 : gnc_numeric_reduce(gnc_numeric in)
    1208                 :             : {
    1209                 :        3291 :     if (gnc_numeric_check(in))
    1210                 :             :     {
    1211                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1212                 :             :     }
    1213                 :             : 
    1214                 :        3291 :     if (in.denom < 0) /* Negative denoms multiply num, can't be reduced. */
    1215                 :           0 :         return in;
    1216                 :             :     try
    1217                 :             :     {
    1218                 :        3291 :         GncNumeric an (in);
    1219                 :        3291 :         return static_cast<gnc_numeric>(an.reduce());
    1220                 :             :     }
    1221                 :           0 :     catch (const std::overflow_error& err)
    1222                 :             :     {
    1223                 :           0 :         PWARN("%s", err.what());
    1224                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1225                 :           0 :     }
    1226                 :           0 :     catch (const std::invalid_argument& err)
    1227                 :             :     {
    1228                 :           0 :         PWARN("%s", err.what());
    1229                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1230                 :           0 :     }
    1231                 :           0 :     catch (const std::underflow_error& err)
    1232                 :             :     {
    1233                 :           0 :         PWARN("%s", err.what());
    1234                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1235                 :           0 :     }
    1236                 :           0 :     catch (const std::domain_error& err)
    1237                 :             :     {
    1238                 :           0 :         PWARN("%s", err.what());
    1239                 :           0 :         return gnc_numeric_error(GNC_ERROR_REMAINDER);
    1240                 :           0 :     }
    1241                 :             : }
    1242                 :             : 
    1243                 :             : 
    1244                 :             : /* *******************************************************************
    1245                 :             :  * gnc_numeric_to_decimal
    1246                 :             :  *
    1247                 :             :  * Attempt to convert the denominator to an exact power of ten without
    1248                 :             :  * rounding. TRUE is returned if 'a' has been converted or was already
    1249                 :             :  * decimal. Otherwise, FALSE is returned and 'a' remains unchanged.
    1250                 :             :  * The 'max_decimal_places' parameter may be NULL.
    1251                 :             :  ********************************************************************/
    1252                 :             : 
    1253                 :             : gboolean
    1254                 :      129714 : gnc_numeric_to_decimal(gnc_numeric *a, guint8 *max_decimal_places)
    1255                 :             : {
    1256                 :      129714 :     int max_places =  max_decimal_places == NULL ? max_leg_digits :
    1257                 :             :         *max_decimal_places;
    1258                 :      129714 :     if (a->num == 0) return TRUE;
    1259                 :             :     try
    1260                 :             :     {
    1261                 :       32117 :         GncNumeric an (*a);
    1262                 :       32117 :         auto bn = an.to_decimal(max_places);
    1263                 :       32031 :         *a = static_cast<gnc_numeric>(bn);
    1264                 :       32031 :         return TRUE;
    1265                 :             :     }
    1266                 :          86 :     catch (const std::exception& err)
    1267                 :             :     {
    1268                 :          86 :         PINFO ("%s", err.what());
    1269                 :          86 :         return FALSE;
    1270                 :          86 :     }
    1271                 :             : }
    1272                 :             : 
    1273                 :             : 
    1274                 :             : gnc_numeric
    1275                 :         708 : gnc_numeric_invert(gnc_numeric num)
    1276                 :             : {
    1277                 :         708 :     if (num.num == 0)
    1278                 :           0 :         return gnc_numeric_zero();
    1279                 :             :     try
    1280                 :             :     {
    1281                 :         708 :         return static_cast<gnc_numeric>(GncNumeric(num).inv());
    1282                 :             :     }
    1283                 :           0 :     catch (const std::overflow_error& err)
    1284                 :             :     {
    1285                 :           0 :         PWARN("%s", err.what());
    1286                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1287                 :           0 :     }
    1288                 :           0 :     catch (const std::invalid_argument& err)
    1289                 :             :     {
    1290                 :           0 :         PWARN("%s", err.what());
    1291                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1292                 :           0 :     }
    1293                 :           0 :     catch (const std::underflow_error& err)
    1294                 :             :     {
    1295                 :           0 :         PWARN("%s", err.what());
    1296                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1297                 :           0 :     }
    1298                 :           0 :     catch (const std::domain_error& err)
    1299                 :             :     {
    1300                 :           0 :         PWARN("%s", err.what());
    1301                 :           0 :         return gnc_numeric_error(GNC_ERROR_REMAINDER);
    1302                 :           0 :     }
    1303                 :             : }
    1304                 :             : 
    1305                 :             : /* *******************************************************************
    1306                 :             :  *  double_to_gnc_numeric
    1307                 :             :  ********************************************************************/
    1308                 :             : 
    1309                 :             : #ifdef _MSC_VER
    1310                 :             : # define rint /* */
    1311                 :             : #endif
    1312                 :             : gnc_numeric
    1313                 :         362 : double_to_gnc_numeric(double in, gint64 denom, gint how)
    1314                 :             : {
    1315                 :             :     try
    1316                 :             :     {
    1317                 :         362 :         GncNumeric an(in);
    1318                 :         362 :         return convert(an, denom, how);
    1319                 :             :     }
    1320                 :           0 :     catch (const std::overflow_error& err)
    1321                 :             :     {
    1322                 :           0 :         PWARN("%s", err.what());
    1323                 :           0 :         return gnc_numeric_error(GNC_ERROR_OVERFLOW);
    1324                 :           0 :     }
    1325                 :           0 :     catch (const std::invalid_argument& err)
    1326                 :             :     {
    1327                 :           0 :         PWARN("%s", err.what());
    1328                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1329                 :           0 :     }
    1330                 :           0 :     catch (const std::underflow_error& err)
    1331                 :             :     {
    1332                 :           0 :         PWARN("%s", err.what());
    1333                 :           0 :         return gnc_numeric_error(GNC_ERROR_ARG);
    1334                 :           0 :     }
    1335                 :           0 :     catch (const std::domain_error& err)
    1336                 :             :     {
    1337                 :           0 :         PWARN("%s", err.what());
    1338                 :           0 :         return gnc_numeric_error(GNC_ERROR_REMAINDER);
    1339                 :           0 :     }
    1340                 :             : }
    1341                 :             : 
    1342                 :             : /* *******************************************************************
    1343                 :             :  *  gnc_numeric_to_double
    1344                 :             :  ********************************************************************/
    1345                 :             : 
    1346                 :             : double
    1347                 :         156 : gnc_numeric_to_double(gnc_numeric in)
    1348                 :             : {
    1349                 :         156 :     if (in.denom > 0)
    1350                 :             :     {
    1351                 :         133 :         return (double)in.num / (double)in.denom;
    1352                 :             :     }
    1353                 :             :     else
    1354                 :             :     {
    1355                 :          23 :         return (double)(in.num * -in.denom);
    1356                 :             :     }
    1357                 :             : }
    1358                 :             : 
    1359                 :             : /* *******************************************************************
    1360                 :             :  *  gnc_numeric_error
    1361                 :             :  ********************************************************************/
    1362                 :             : 
    1363                 :             : gnc_numeric
    1364                 :         324 : gnc_numeric_error(GNCNumericErrorCode error_code)
    1365                 :             : {
    1366                 :         324 :     return gnc_numeric_create(error_code, 0LL);
    1367                 :             : }
    1368                 :             : 
    1369                 :             : 
    1370                 :             : 
    1371                 :             : /* *******************************************************************
    1372                 :             :  *  gnc_numeric text IO
    1373                 :             :  ********************************************************************/
    1374                 :             : 
    1375                 :             : gchar *
    1376                 :        8138 : gnc_numeric_to_string(gnc_numeric n)
    1377                 :             : {
    1378                 :             :     char *result;
    1379                 :        8138 :     int64_t tmpnum = n.num;
    1380                 :        8138 :     int64_t tmpdenom = n.denom;
    1381                 :             : 
    1382                 :        8138 :     result = g_strdup_printf("%" PRId64 "/%" PRId64, tmpnum, tmpdenom);
    1383                 :             : 
    1384                 :        8138 :     return result;
    1385                 :             : }
    1386                 :             : 
    1387                 :             : gchar *
    1388                 :          36 : gnc_num_dbg_to_string(gnc_numeric n)
    1389                 :             : {
    1390                 :             :     static char buff[1000];
    1391                 :             :     static char *p = buff;
    1392                 :             :     static const size_t size = 50;
    1393                 :          36 :     int64_t tmpnum = n.num;
    1394                 :          36 :     int64_t tmpdenom = n.denom;
    1395                 :             : 
    1396                 :          36 :     p += size;
    1397                 :          36 :     if ((size_t)(p - buff) > (sizeof(buff) - size))
    1398                 :           1 :         p = buff;
    1399                 :             : 
    1400                 :          36 :     snprintf(p, size, "%" PRId64 "/%" PRId64, tmpnum, tmpdenom);
    1401                 :             : 
    1402                 :          36 :     return p;
    1403                 :             : }
    1404                 :             : 
    1405                 :             : gnc_numeric
    1406                 :        5144 : gnc_numeric_from_string (const gchar* str)
    1407                 :             : {
    1408                 :        5144 :     if (!str)
    1409                 :           0 :         return gnc_numeric_error (GNC_ERROR_ARG);
    1410                 :             : 
    1411                 :             :     // the default gnc_numeric string format is "num/denom", whereby
    1412                 :             :     // the denom must be >= 1. this speedily parses it. this also
    1413                 :             :     // parses "num" as num/1.
    1414                 :        5144 :     if (auto res = fast_numeral_rational (str))
    1415                 :        5135 :         return *res;
    1416                 :             : 
    1417                 :             :     try
    1418                 :             :     {
    1419                 :          18 :         return GncNumeric (str);
    1420                 :             :     }
    1421                 :           3 :     catch (const std::exception& err)
    1422                 :             :     {
    1423                 :           3 :         PWARN("%s", err.what());
    1424                 :           3 :         return gnc_numeric_error (GNC_ERROR_ARG);
    1425                 :           3 :     }
    1426                 :             : }
    1427                 :             : 
    1428                 :             : /* *******************************************************************
    1429                 :             :  *  GValue handling
    1430                 :             :  ********************************************************************/
    1431                 :             : static gnc_numeric*
    1432                 :         513 : gnc_numeric_boxed_copy_func( gnc_numeric *in_gnc_numeric )
    1433                 :             : {
    1434                 :         513 :     if (!in_gnc_numeric)
    1435                 :           0 :         return nullptr;
    1436                 :             : 
    1437                 :             :     /* newvalue will be passed to g_free so we must allocate with g_malloc. */
    1438                 :         513 :     auto newvalue = static_cast<gnc_numeric*>(g_malloc (sizeof (gnc_numeric)));
    1439                 :         513 :     *newvalue = *in_gnc_numeric;
    1440                 :             : 
    1441                 :         513 :     return newvalue;
    1442                 :             : }
    1443                 :             : 
    1444                 :             : static void
    1445                 :         461 : gnc_numeric_boxed_free_func( gnc_numeric *in_gnc_numeric )
    1446                 :             : {
    1447                 :         461 :     g_free( in_gnc_numeric );
    1448                 :         461 : }
    1449                 :             : 
    1450                 :        4872 : G_DEFINE_BOXED_TYPE (gnc_numeric, gnc_numeric, gnc_numeric_boxed_copy_func, gnc_numeric_boxed_free_func)
    1451                 :             : 
    1452                 :             : /* *******************************************************************
    1453                 :             :  *  gnc_numeric misc testing
    1454                 :             :  ********************************************************************/
    1455                 :             : #ifdef _GNC_NUMERIC_TEST
    1456                 :             : 
    1457                 :             : static char *
    1458                 :             : gnc_numeric_print(gnc_numeric in)
    1459                 :             : {
    1460                 :             :     char * retval;
    1461                 :             :     if (gnc_numeric_check(in))
    1462                 :             :     {
    1463                 :             :         retval = g_strdup_printf("<ERROR> [%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
    1464                 :             :                                  in.num,
    1465                 :             :                                  in.denom);
    1466                 :             :     }
    1467                 :             :     else
    1468                 :             :     {
    1469                 :             :         retval = g_strdup_printf("[%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
    1470                 :             :                                  in.num,
    1471                 :             :                                  in.denom);
    1472                 :             :     }
    1473                 :             :     return retval;
    1474                 :             : }
    1475                 :             : 
    1476                 :             : int
    1477                 :             : main(int argc, char ** argv)
    1478                 :             : {
    1479                 :             :     gnc_numeric a = gnc_numeric_create(1, 3);
    1480                 :             :     gnc_numeric b = gnc_numeric_create(1, 4);
    1481                 :             :     gnc_numeric c;
    1482                 :             : 
    1483                 :             :     gnc_numeric err;
    1484                 :             : 
    1485                 :             : 
    1486                 :             :     printf("multiply (EXACT): %s * %s = %s\n",
    1487                 :             :            gnc_numeric_print(a), gnc_numeric_print(b),
    1488                 :             :            gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT)));
    1489                 :             : 
    1490                 :             :     printf("multiply (REDUCE): %s * %s = %s\n",
    1491                 :             :            gnc_numeric_print(a), gnc_numeric_print(b),
    1492                 :             :            gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE)));
    1493                 :             : 
    1494                 :             : 
    1495                 :             :     return 0;
    1496                 :             : }
    1497                 :             : #endif
    1498                 :             : 
    1499                 :             : 
    1500                 :             : std::ostream&
    1501                 :         284 : operator<<(std::ostream& s, GncNumeric n)
    1502                 :             : {
    1503                 :             :     using boost::locale::conv::utf_to_utf;
    1504                 :         284 :     std::basic_ostringstream<wchar_t> ss;
    1505                 :         284 :     ss.imbue(s.getloc());
    1506                 :         284 :     ss << n;
    1507                 :         284 :     s << utf_to_utf<char>(ss.str());
    1508                 :         284 :     return s;
    1509                 :         284 : }
    1510                 :             : 
    1511                 :           6 : const char* gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
    1512                 :             : {
    1513                 :           6 :     switch (error_code)
    1514                 :             :     {
    1515                 :           6 :     case GNC_ERROR_OK:
    1516                 :           6 :         return "GNC_ERROR_OK";
    1517                 :           0 :     case GNC_ERROR_ARG:
    1518                 :           0 :         return "GNC_ERROR_ARG";
    1519                 :           0 :     case GNC_ERROR_OVERFLOW:
    1520                 :           0 :         return "GNC_ERROR_OVERFLOW";
    1521                 :           0 :     case GNC_ERROR_DENOM_DIFF:
    1522                 :           0 :         return "GNC_ERROR_DENOM_DIFF";
    1523                 :           0 :     case GNC_ERROR_REMAINDER:
    1524                 :           0 :         return "GNC_ERROR_REMAINDER";
    1525                 :           0 :     default:
    1526                 :           0 :         return "<unknown>";
    1527                 :             :     }
    1528                 :             : }
    1529                 :             : 
    1530                 :             : /* ======================== END OF FILE =================== */
        

Generated by: LCOV version 2.0-1