2001-08-07 18:36:04 -05:00
|
|
|
/********************************************************************
|
2003-06-09 10:45:40 -05:00
|
|
|
* gnc-numeric.c -- an exact-number library for accounting use *
|
2001-08-07 18:36:04 -05:00
|
|
|
* Copyright (C) 2000 Bill Gribble *
|
2004-06-25 19:18:17 -05:00
|
|
|
* Copyright (C) 2004 Linas Vepstas <linas@linas.org> *
|
2001-08-07 18:36:04 -05:00
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or *
|
|
|
|
* modify it under the terms of the GNU General Public License as *
|
|
|
|
* published by the Free Software Foundation; either version 2 of *
|
|
|
|
* the License, or (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License*
|
|
|
|
* along with this program; if not, contact: *
|
|
|
|
* *
|
|
|
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
2005-11-16 23:35:02 -06:00
|
|
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
|
|
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
2001-08-07 18:36:04 -05:00
|
|
|
* *
|
|
|
|
*******************************************************************/
|
2014-04-25 15:41:11 -05:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
#endif
|
2001-08-07 18:36:04 -05:00
|
|
|
|
2001-09-07 16:51:13 -05:00
|
|
|
#include "config.h"
|
|
|
|
|
2001-08-07 18:36:04 -05:00
|
|
|
#include <glib.h>
|
2003-06-09 10:45:40 -05:00
|
|
|
#include <math.h>
|
2001-08-07 18:36:04 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2003-06-09 10:45:40 -05:00
|
|
|
#include <string.h>
|
2014-04-25 15:41:11 -05:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
2001-08-07 18:36:04 -05:00
|
|
|
|
|
|
|
#include "gnc-numeric.h"
|
2014-12-04 13:48:08 -06:00
|
|
|
#include "gnc-rational.hpp"
|
|
|
|
|
|
|
|
using GncNumeric = GncRational;
|
2001-08-07 18:36:04 -05:00
|
|
|
|
2014-01-19 15:22:01 -06:00
|
|
|
static const gint64 pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
|
|
|
|
10000000, 100000000, 1000000000, 10000000000,
|
|
|
|
100000000000, 1000000000000, 10000000000000,
|
2014-06-08 15:46:56 -05:00
|
|
|
100000000000000, 10000000000000000,
|
2014-06-09 10:34:20 -05:00
|
|
|
100000000000000000, 1000000000000000000};
|
2014-12-04 13:48:08 -06:00
|
|
|
static const int POWTEN_OVERFLOW {-5};
|
2014-01-19 15:22:01 -06:00
|
|
|
|
|
|
|
static inline gint64
|
|
|
|
powten (int exp)
|
|
|
|
{
|
2014-06-09 10:34:20 -05:00
|
|
|
if (exp > 18 || exp < -18)
|
2014-01-19 15:22:01 -06:00
|
|
|
return POWTEN_OVERFLOW;
|
|
|
|
return exp < 0 ? -pten[-exp] : pten[exp];
|
|
|
|
}
|
2014-11-29 19:53:41 -06:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
|
2014-11-29 19:53:41 -06:00
|
|
|
/* =============================================================== */
|
|
|
|
/* This function is small, simple, and used everywhere below,
|
|
|
|
* lets try to inline it.
|
|
|
|
*/
|
|
|
|
GNCNumericErrorCode
|
|
|
|
gnc_numeric_check(gnc_numeric in)
|
|
|
|
{
|
|
|
|
if (G_LIKELY(in.denom != 0))
|
2009-09-18 14:40:57 -05:00
|
|
|
{
|
2014-11-29 19:53:41 -06:00
|
|
|
return GNC_ERROR_OK;
|
|
|
|
}
|
|
|
|
else if (in.num)
|
|
|
|
{
|
|
|
|
if ((0 < in.num) || (-4 > in.num))
|
|
|
|
{
|
|
|
|
in.num = (gint64) GNC_ERROR_OVERFLOW;
|
|
|
|
}
|
|
|
|
return (GNCNumericErrorCode) in.num;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return GNC_ERROR_ARG;
|
2009-09-18 14:40:57 -05:00
|
|
|
}
|
2004-06-28 22:50:59 -05:00
|
|
|
}
|
|
|
|
|
2014-11-29 19:53:41 -06:00
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_zero_p
|
|
|
|
********************************************************************/
|
|
|
|
|
2004-06-26 21:26:28 -05:00
|
|
|
gboolean
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_zero_p(gnc_numeric a)
|
2004-06-26 21:26:28 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if (gnc_numeric_check(a))
|
2004-06-26 21:26:28 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
return 0;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
2009-09-18 14:40:57 -05:00
|
|
|
else
|
2004-06-26 21:26:28 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if ((a.num == 0) && (a.denom != 0))
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_negative_p
|
|
|
|
********************************************************************/
|
|
|
|
|
2004-06-26 21:26:28 -05:00
|
|
|
gboolean
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_negative_p(gnc_numeric a)
|
2004-06-26 21:26:28 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if (gnc_numeric_check(a))
|
2004-06-26 21:26:28 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
return 0;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
2009-09-18 14:40:57 -05:00
|
|
|
else
|
2004-06-26 21:26:28 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if ((a.num < 0) && (a.denom != 0))
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_positive_p
|
|
|
|
********************************************************************/
|
|
|
|
|
2004-06-26 21:26:28 -05:00
|
|
|
gboolean
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_positive_p(gnc_numeric a)
|
2004-06-26 21:26:28 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if (gnc_numeric_check(a))
|
2004-06-26 21:26:28 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
return 0;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
2009-09-18 14:40:57 -05:00
|
|
|
else
|
2004-06-26 21:26:28 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if ((a.num > 0) && (a.denom != 0))
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-29 19:53:41 -06:00
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_compare
|
2009-09-18 14:40:57 -05:00
|
|
|
* returns 1 if a>b, -1 if b>a, 0 if a == b
|
2001-08-07 18:36:04 -05:00
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
int
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
|
2004-07-03 22:56:40 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
gint64 aa, bb;
|
2001-08-07 18:36:04 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
if (gnc_numeric_check(a) || gnc_numeric_check(b))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2001-08-07 18:36:04 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
if (a.denom == b.denom)
|
|
|
|
{
|
|
|
|
if (a.num == b.num) return 0;
|
|
|
|
if (a.num > b.num) return 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-11-29 19:53:41 -06:00
|
|
|
GncNumeric an (a), bn (b);
|
2009-09-18 14:40:57 -05:00
|
|
|
|
2014-11-29 19:53:41 -06:00
|
|
|
return (an.m_num * bn.m_den).cmp(bn.m_num * an.m_den);
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_eq
|
|
|
|
********************************************************************/
|
|
|
|
|
2004-06-25 19:18:17 -05:00
|
|
|
gboolean
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
|
2004-06-25 19:18:17 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
return ((a.num == b.num) && (a.denom == b.denom));
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_equal
|
|
|
|
********************************************************************/
|
|
|
|
|
2004-06-25 19:18:17 -05:00
|
|
|
gboolean
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
|
2004-06-25 19:18:17 -05:00
|
|
|
{
|
2014-11-29 19:53:41 -06:00
|
|
|
return gnc_numeric_compare (a, b) == 0;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_same
|
2009-09-18 14:40:57 -05:00
|
|
|
* would a and b be equal() if they were both converted to the same
|
|
|
|
* denominator?
|
2001-08-07 18:36:04 -05:00
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
int
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom,
|
|
|
|
gint how)
|
|
|
|
{
|
|
|
|
gnc_numeric aconv, bconv;
|
|
|
|
|
|
|
|
aconv = gnc_numeric_convert(a, denom, how);
|
|
|
|
bconv = gnc_numeric_convert(b, denom, how);
|
|
|
|
|
|
|
|
return(gnc_numeric_equal(aconv, bconv));
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_add
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_add(gnc_numeric a, gnc_numeric b,
|
|
|
|
gint64 denom, gint how)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if (gnc_numeric_check(a) || gnc_numeric_check(b))
|
|
|
|
{
|
|
|
|
return gnc_numeric_error(GNC_ERROR_ARG);
|
|
|
|
}
|
|
|
|
|
2014-11-29 19:53:41 -06:00
|
|
|
GncNumeric an (a), bn (b);
|
|
|
|
GncDenom new_denom (an, bn, denom, how);
|
|
|
|
if (new_denom.m_error)
|
|
|
|
return gnc_numeric_error (new_denom.m_error);
|
2009-09-18 14:40:57 -05:00
|
|
|
|
|
|
|
|
2014-12-05 16:50:23 -06:00
|
|
|
return static_cast<gnc_numeric>(an.add(bn, new_denom));
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_sub
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
|
|
|
|
gint64 denom, gint how)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric nb;
|
|
|
|
if (gnc_numeric_check(a) || gnc_numeric_check(b))
|
|
|
|
{
|
|
|
|
return gnc_numeric_error(GNC_ERROR_ARG);
|
|
|
|
}
|
|
|
|
|
|
|
|
nb = b;
|
|
|
|
nb.num = -nb.num;
|
|
|
|
return gnc_numeric_add (a, nb, denom, how);
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_mul
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
|
|
|
|
gint64 denom, gint how)
|
2003-08-10 15:10:28 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if (gnc_numeric_check(a) || gnc_numeric_check(b))
|
|
|
|
{
|
|
|
|
return gnc_numeric_error(GNC_ERROR_ARG);
|
|
|
|
}
|
|
|
|
|
2014-11-29 19:53:41 -06:00
|
|
|
GncNumeric an (a), bn (b);
|
|
|
|
GncDenom new_denom (an, bn, denom, how);
|
|
|
|
if (new_denom.m_error)
|
|
|
|
return gnc_numeric_error (new_denom.m_error);
|
2004-07-06 08:42:39 -05:00
|
|
|
|
2014-12-05 16:50:23 -06:00
|
|
|
return static_cast<gnc_numeric>(an.mul(bn, new_denom));
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_div
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_div(gnc_numeric a, gnc_numeric b,
|
|
|
|
gint64 denom, gint how)
|
2004-06-26 10:36:38 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if (gnc_numeric_check(a) || gnc_numeric_check(b))
|
2004-06-26 18:01:38 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
return gnc_numeric_error(GNC_ERROR_ARG);
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
2009-09-18 14:40:57 -05:00
|
|
|
|
2014-11-29 19:53:41 -06:00
|
|
|
GncNumeric an (a), bn (b);
|
|
|
|
GncDenom new_denom (an, bn, denom, how);
|
|
|
|
if (new_denom.m_error)
|
|
|
|
return gnc_numeric_error (new_denom.m_error);
|
2004-07-07 01:20:44 -05:00
|
|
|
|
2014-12-05 16:50:23 -06:00
|
|
|
return static_cast<gnc_numeric>(an.div(bn, new_denom));
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
2009-09-18 14:40:57 -05:00
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_neg
|
2009-09-18 14:40:57 -05:00
|
|
|
* negate the argument
|
2001-08-07 18:36:04 -05:00
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_neg(gnc_numeric a)
|
|
|
|
{
|
|
|
|
if (gnc_numeric_check(a))
|
|
|
|
{
|
|
|
|
return gnc_numeric_error(GNC_ERROR_ARG);
|
|
|
|
}
|
|
|
|
return gnc_numeric_create(- a.num, a.denom);
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2010-08-14 04:30:10 -05:00
|
|
|
* gnc_numeric_abs
|
2009-09-18 14:40:57 -05:00
|
|
|
* return the absolute value of the argument
|
2001-08-07 18:36:04 -05:00
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_abs(gnc_numeric a)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if (gnc_numeric_check(a))
|
|
|
|
{
|
|
|
|
return gnc_numeric_error(GNC_ERROR_ARG);
|
|
|
|
}
|
|
|
|
return gnc_numeric_create(ABS(a.num), a.denom);
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
2014-11-29 19:53:41 -06:00
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_convert
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2014-12-10 17:40:13 -06:00
|
|
|
gnc_numeric_convert(gnc_numeric in, gint64 denom, int how)
|
2003-08-10 15:10:28 -05:00
|
|
|
{
|
2014-11-29 19:53:41 -06:00
|
|
|
GncNumeric a (in), b (gnc_numeric_zero());
|
|
|
|
GncDenom d (a, b, denom, how);
|
|
|
|
a.round (d);
|
|
|
|
return static_cast<gnc_numeric>(a);
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
|
|
|
* reduce a fraction by GCF elimination. This is NOT done as a
|
2009-09-18 14:40:57 -05:00
|
|
|
* part of the arithmetic API unless GNC_HOW_DENOM_REDUCE is specified
|
2001-08-07 18:36:04 -05:00
|
|
|
* as the output denominator.
|
|
|
|
********************************************************************/
|
|
|
|
|
2003-01-08 19:06:27 -06:00
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_reduce(gnc_numeric in)
|
2004-05-29 20:47:37 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if (gnc_numeric_check(in))
|
|
|
|
{
|
|
|
|
return gnc_numeric_error(GNC_ERROR_ARG);
|
|
|
|
}
|
|
|
|
|
2014-11-29 19:53:41 -06:00
|
|
|
if (in.denom < 0) /* Negative denoms multiply num, can't be reduced. */
|
|
|
|
return in;
|
|
|
|
GncNumeric a (in), b (gnc_numeric_zero());
|
|
|
|
GncDenom d (a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
|
|
|
|
a.round (d);
|
|
|
|
return static_cast<gnc_numeric>(a);
|
2003-01-08 19:06:27 -06:00
|
|
|
}
|
|
|
|
|
2008-07-27 10:33:23 -05:00
|
|
|
|
|
|
|
/* *******************************************************************
|
|
|
|
* gnc_numeric_to_decimal
|
|
|
|
*
|
|
|
|
* Attempt to convert the denominator to an exact power of ten without
|
|
|
|
* rounding. TRUE is returned if 'a' has been converted or was already
|
|
|
|
* decimal. Otherwise, FALSE is returned and 'a' remains unchanged.
|
|
|
|
* The 'max_decimal_places' parameter may be NULL.
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gnc_numeric_to_decimal(gnc_numeric *a, guint8 *max_decimal_places)
|
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
guint8 decimal_places = 0;
|
|
|
|
gnc_numeric converted_val;
|
|
|
|
gint64 fraction;
|
2008-07-27 10:33:23 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
g_return_val_if_fail(a, FALSE);
|
2008-07-27 10:33:23 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
if (gnc_numeric_check(*a) != GNC_ERROR_OK)
|
|
|
|
return FALSE;
|
2008-08-07 13:18:00 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
converted_val = *a;
|
|
|
|
if (converted_val.denom <= 0)
|
2008-07-27 10:33:23 -05:00
|
|
|
{
|
2010-08-26 12:22:06 -05:00
|
|
|
converted_val = gnc_numeric_convert(converted_val, 1, GNC_HOW_DENOM_EXACT);
|
2008-07-27 10:33:23 -05:00
|
|
|
if (gnc_numeric_check(converted_val) != GNC_ERROR_OK)
|
2009-09-18 14:40:57 -05:00
|
|
|
return FALSE;
|
|
|
|
*a = converted_val;
|
|
|
|
if (max_decimal_places)
|
|
|
|
*max_decimal_places = decimal_places;
|
|
|
|
return TRUE;
|
|
|
|
}
|
2008-07-27 10:33:23 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
/* Zero is easily converted. */
|
|
|
|
if (converted_val.num == 0)
|
|
|
|
converted_val.denom = 1;
|
2008-07-27 10:33:23 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
fraction = converted_val.denom;
|
|
|
|
while (fraction != 1)
|
|
|
|
{
|
|
|
|
switch (fraction % 10)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
fraction = fraction / 10;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5:
|
|
|
|
converted_val = gnc_numeric_mul(converted_val,
|
|
|
|
gnc_numeric_create(2, 2),
|
|
|
|
GNC_DENOM_AUTO,
|
|
|
|
GNC_HOW_DENOM_EXACT |
|
|
|
|
GNC_HOW_RND_NEVER);
|
|
|
|
if (gnc_numeric_check(converted_val) != GNC_ERROR_OK)
|
|
|
|
return FALSE;
|
|
|
|
fraction = fraction / 5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
case 4:
|
|
|
|
case 6:
|
|
|
|
case 8:
|
|
|
|
converted_val = gnc_numeric_mul(converted_val,
|
|
|
|
gnc_numeric_create(5, 5),
|
|
|
|
GNC_DENOM_AUTO,
|
|
|
|
GNC_HOW_DENOM_EXACT |
|
|
|
|
GNC_HOW_RND_NEVER);
|
|
|
|
if (gnc_numeric_check(converted_val) != GNC_ERROR_OK)
|
|
|
|
return FALSE;
|
|
|
|
fraction = fraction / 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
2008-07-27 10:33:23 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
decimal_places += 1;
|
|
|
|
}
|
2008-07-27 10:33:23 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
if (max_decimal_places)
|
|
|
|
*max_decimal_places = decimal_places;
|
2008-07-27 10:33:23 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
*a = converted_val;
|
2008-07-27 10:33:23 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
return TRUE;
|
2008-07-27 10:33:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* double_to_gnc_numeric
|
|
|
|
********************************************************************/
|
|
|
|
|
2010-02-27 12:40:23 -06:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
# define rint /* */
|
|
|
|
#endif
|
2001-08-07 18:36:04 -05:00
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
double_to_gnc_numeric(double in, gint64 denom, gint how)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric out;
|
|
|
|
gint64 int_part = 0;
|
|
|
|
double frac_part;
|
|
|
|
gint64 frac_int = 0;
|
|
|
|
double logval;
|
|
|
|
double sigfigs;
|
|
|
|
|
2014-06-08 15:46:56 -05:00
|
|
|
if (isnan (in) || fabs (in) > 1e18)
|
|
|
|
return gnc_numeric_error (GNC_ERROR_OVERFLOW);
|
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
if ((denom == GNC_DENOM_AUTO) && (how & GNC_HOW_DENOM_SIGFIG))
|
|
|
|
{
|
|
|
|
if (fabs(in) < 10e-20)
|
|
|
|
{
|
|
|
|
logval = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
logval = log10(fabs(in));
|
|
|
|
logval = ((logval > 0.0) ?
|
|
|
|
(floor(logval) + 1.0) : (ceil(logval)));
|
|
|
|
}
|
|
|
|
sigfigs = GNC_HOW_GET_SIGFIGS(how);
|
2014-01-19 15:22:01 -06:00
|
|
|
if ((denom = powten (sigfigs - logval)) == POWTEN_OVERFLOW)
|
|
|
|
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
2009-09-18 14:40:57 -05:00
|
|
|
|
|
|
|
how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int_part = (gint64)(floor(fabs(in)));
|
|
|
|
frac_part = in - (double)int_part;
|
|
|
|
|
|
|
|
int_part = int_part * denom;
|
|
|
|
frac_part = frac_part * (double)denom;
|
|
|
|
|
|
|
|
switch (how & GNC_NUMERIC_RND_MASK)
|
|
|
|
{
|
|
|
|
case GNC_HOW_RND_FLOOR:
|
|
|
|
frac_int = (gint64)floor(frac_part);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GNC_HOW_RND_CEIL:
|
|
|
|
frac_int = (gint64)ceil(frac_part);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GNC_HOW_RND_TRUNC:
|
|
|
|
frac_int = (gint64)frac_part;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GNC_HOW_RND_ROUND:
|
|
|
|
case GNC_HOW_RND_ROUND_HALF_UP:
|
|
|
|
frac_int = (gint64)rint(frac_part);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GNC_HOW_RND_NEVER:
|
|
|
|
frac_int = (gint64)floor(frac_part);
|
|
|
|
if (frac_part != (double) frac_int)
|
|
|
|
{
|
|
|
|
/* signal an error */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
out.num = int_part + frac_int;
|
|
|
|
out.denom = denom;
|
|
|
|
return out;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_to_double
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
double
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_to_double(gnc_numeric in)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
if (in.denom > 0)
|
|
|
|
{
|
|
|
|
return (double)in.num / (double)in.denom;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return (double)(in.num * -in.denom);
|
|
|
|
}
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_error
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_error(GNCNumericErrorCode error_code)
|
2004-05-29 17:43:49 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
return gnc_numeric_create(error_code, 0LL);
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_add_with_error
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b,
|
2001-08-07 18:36:04 -05:00
|
|
|
gint64 denom, gint how,
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric * error)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2001-08-07 18:36:04 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric sum = gnc_numeric_add(a, b, denom, how);
|
|
|
|
gnc_numeric exact = gnc_numeric_add(a, b, GNC_DENOM_AUTO,
|
|
|
|
GNC_HOW_DENOM_REDUCE);
|
|
|
|
gnc_numeric err = gnc_numeric_sub(sum, exact, GNC_DENOM_AUTO,
|
|
|
|
GNC_HOW_DENOM_REDUCE);
|
2001-08-07 18:36:04 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
*error = err;
|
|
|
|
}
|
|
|
|
return sum;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_sub_with_error
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
|
2001-08-07 18:36:04 -05:00
|
|
|
gint64 denom, gint how,
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric * error)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric diff = gnc_numeric_sub(a, b, denom, how);
|
|
|
|
gnc_numeric exact = gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
|
|
|
|
GNC_HOW_DENOM_REDUCE);
|
|
|
|
gnc_numeric err = gnc_numeric_sub(diff, exact, GNC_DENOM_AUTO,
|
|
|
|
GNC_HOW_DENOM_REDUCE);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
*error = err;
|
|
|
|
}
|
|
|
|
return diff;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_mul_with_error
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b,
|
2001-08-07 18:36:04 -05:00
|
|
|
gint64 denom, gint how,
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric * error)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric prod = gnc_numeric_mul(a, b, denom, how);
|
|
|
|
gnc_numeric exact = gnc_numeric_mul(a, b, GNC_DENOM_AUTO,
|
|
|
|
GNC_HOW_DENOM_REDUCE);
|
|
|
|
gnc_numeric err = gnc_numeric_sub(prod, exact, GNC_DENOM_AUTO,
|
|
|
|
GNC_HOW_DENOM_REDUCE);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
*error = err;
|
|
|
|
}
|
|
|
|
return prod;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric_div_with_error
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gnc_numeric
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
|
2001-08-07 18:36:04 -05:00
|
|
|
gint64 denom, gint how,
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric * error)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric quot = gnc_numeric_div(a, b, denom, how);
|
|
|
|
gnc_numeric exact = gnc_numeric_div(a, b, GNC_DENOM_AUTO,
|
|
|
|
GNC_HOW_DENOM_REDUCE);
|
|
|
|
gnc_numeric err = gnc_numeric_sub(quot, exact,
|
|
|
|
GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
*error = err;
|
|
|
|
}
|
|
|
|
return quot;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2001-08-07 18:36:04 -05:00
|
|
|
* gnc_numeric text IO
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
gchar *
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_to_string(gnc_numeric n)
|
2004-05-29 20:47:37 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
gchar *result;
|
|
|
|
gint64 tmpnum = n.num;
|
|
|
|
gint64 tmpdenom = n.denom;
|
2001-08-07 18:36:04 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
result = g_strdup_printf("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom);
|
2001-08-07 18:36:04 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
return result;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
2004-07-04 12:26:50 -05:00
|
|
|
gchar *
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_num_dbg_to_string(gnc_numeric n)
|
2004-07-04 12:26:50 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
static char buff[1000];
|
|
|
|
static char *p = buff;
|
|
|
|
gint64 tmpnum = n.num;
|
|
|
|
gint64 tmpdenom = n.denom;
|
|
|
|
|
|
|
|
p += 100;
|
|
|
|
if (p - buff >= 1000) p = buff;
|
2004-07-04 12:26:50 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
sprintf(p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom);
|
2004-07-04 12:26:50 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
return p;
|
2004-07-04 12:26:50 -05:00
|
|
|
}
|
|
|
|
|
2004-10-31 19:37:10 -06:00
|
|
|
gboolean
|
2009-09-18 14:40:57 -05:00
|
|
|
string_to_gnc_numeric(const gchar* str, gnc_numeric *n)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
gint64 tmpnum;
|
|
|
|
gint64 tmpdenom;
|
|
|
|
|
|
|
|
if (!str) return FALSE;
|
2001-08-07 18:36:04 -05:00
|
|
|
|
2010-02-27 12:39:15 -06:00
|
|
|
tmpnum = g_ascii_strtoll (str, NULL, 0);
|
2009-09-18 14:40:57 -05:00
|
|
|
str = strchr (str, '/');
|
|
|
|
if (!str) return FALSE;
|
|
|
|
str ++;
|
2010-02-27 12:39:15 -06:00
|
|
|
tmpdenom = g_ascii_strtoll (str, NULL, 0);
|
2012-03-08 16:47:59 -06:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
n->num = tmpnum;
|
|
|
|
n->denom = tmpdenom;
|
|
|
|
return TRUE;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
2007-04-09 18:02:47 -05:00
|
|
|
/* *******************************************************************
|
|
|
|
* GValue handling
|
|
|
|
********************************************************************/
|
|
|
|
static gpointer
|
|
|
|
gnc_numeric_boxed_copy_func( gpointer in_gnc_numeric )
|
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric* newvalue;
|
2007-04-09 18:02:47 -05:00
|
|
|
|
2014-04-25 15:41:11 -05:00
|
|
|
newvalue = static_cast<gnc_numeric*>(g_malloc (sizeof (gnc_numeric)));
|
2009-09-18 14:40:57 -05:00
|
|
|
memcpy( newvalue, in_gnc_numeric, sizeof( gnc_numeric ) );
|
2007-04-09 18:02:47 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
return newvalue;
|
2007-04-09 18:02:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gnc_numeric_boxed_free_func( gpointer in_gnc_numeric )
|
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
g_free( in_gnc_numeric );
|
2007-04-09 18:02:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
GType
|
|
|
|
gnc_numeric_get_type( void )
|
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
static GType type = 0;
|
2007-04-09 18:02:47 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
if ( type == 0 )
|
|
|
|
{
|
|
|
|
type = g_boxed_type_register_static( "gnc_numeric",
|
|
|
|
gnc_numeric_boxed_copy_func,
|
|
|
|
gnc_numeric_boxed_free_func );
|
|
|
|
}
|
2007-04-09 18:02:47 -05:00
|
|
|
|
2009-09-18 14:40:57 -05:00
|
|
|
return type;
|
2007-04-09 18:02:47 -05:00
|
|
|
}
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/* *******************************************************************
|
2004-06-26 01:41:10 -05:00
|
|
|
* gnc_numeric misc testing
|
|
|
|
********************************************************************/
|
2001-08-07 18:36:04 -05:00
|
|
|
#ifdef _GNC_NUMERIC_TEST
|
|
|
|
|
|
|
|
static char *
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric_print(gnc_numeric in)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
char * retval;
|
|
|
|
if (gnc_numeric_check(in))
|
|
|
|
{
|
|
|
|
retval = g_strdup_printf("<ERROR> [%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
|
|
|
|
in.num,
|
|
|
|
in.denom);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
retval = g_strdup_printf("[%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
|
|
|
|
in.num,
|
|
|
|
in.denom);
|
|
|
|
}
|
|
|
|
return retval;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2009-09-18 14:40:57 -05:00
|
|
|
main(int argc, char ** argv)
|
2004-06-26 14:08:13 -05:00
|
|
|
{
|
2009-09-18 14:40:57 -05:00
|
|
|
gnc_numeric a = gnc_numeric_create(1, 3);
|
|
|
|
gnc_numeric b = gnc_numeric_create(1, 4);
|
|
|
|
gnc_numeric c;
|
|
|
|
|
|
|
|
gnc_numeric err;
|
|
|
|
|
|
|
|
c = gnc_numeric_add_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
|
|
|
|
printf("add 100ths/error : %s + %s = %s + (error) %s\n\n",
|
|
|
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
|
|
|
gnc_numeric_print(c),
|
|
|
|
gnc_numeric_print(err));
|
|
|
|
|
|
|
|
c = gnc_numeric_sub_with_error(a, b, 100, GNC_HOW_RND_FLOOR, &err);
|
|
|
|
printf("sub 100ths/error : %s - %s = %s + (error) %s\n\n",
|
|
|
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
|
|
|
gnc_numeric_print(c),
|
|
|
|
gnc_numeric_print(err));
|
|
|
|
|
|
|
|
c = gnc_numeric_mul_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
|
|
|
|
printf("mul 100ths/error : %s * %s = %s + (error) %s\n\n",
|
|
|
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
|
|
|
gnc_numeric_print(c),
|
|
|
|
gnc_numeric_print(err));
|
|
|
|
|
|
|
|
c = gnc_numeric_div_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
|
|
|
|
printf("div 100ths/error : %s / %s = %s + (error) %s\n\n",
|
|
|
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
|
|
|
gnc_numeric_print(c),
|
|
|
|
gnc_numeric_print(err));
|
|
|
|
|
|
|
|
printf("multiply (EXACT): %s * %s = %s\n",
|
|
|
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
|
|
|
gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT)));
|
|
|
|
|
|
|
|
printf("multiply (REDUCE): %s * %s = %s\n",
|
|
|
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
|
|
|
gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE)));
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
2001-08-07 18:36:04 -05:00
|
|
|
}
|
|
|
|
#endif
|
2004-06-26 00:06:43 -05:00
|
|
|
|
2011-02-12 09:53:37 -06:00
|
|
|
const char* gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
|
|
|
|
{
|
|
|
|
switch (error_code)
|
|
|
|
{
|
|
|
|
case GNC_ERROR_OK:
|
|
|
|
return "GNC_ERROR_OK";
|
|
|
|
case GNC_ERROR_ARG:
|
|
|
|
return "GNC_ERROR_ARG";
|
|
|
|
case GNC_ERROR_OVERFLOW:
|
|
|
|
return "GNC_ERROR_OVERFLOW";
|
|
|
|
case GNC_ERROR_DENOM_DIFF:
|
|
|
|
return "GNC_ERROR_DENOM_DIFF";
|
|
|
|
case GNC_ERROR_REMAINDER:
|
|
|
|
return "GNC_ERROR_REMAINDER";
|
|
|
|
default:
|
|
|
|
return "<unknown>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-26 00:06:43 -05:00
|
|
|
/* ======================== END OF FILE =================== */
|