mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
finish folding in the now-obsolete texinfo documentation
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@10106 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
d204341674
commit
fab4674a0e
@ -34,11 +34,6 @@
|
|||||||
|
|
||||||
#include "gnc-numeric.h"
|
#include "gnc-numeric.h"
|
||||||
|
|
||||||
/* TODO
|
|
||||||
* - use longer intermediate values to make operations
|
|
||||||
* 64-bit-overflow-proof
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* static short module = MOD_ENGINE; */
|
/* static short module = MOD_ENGINE; */
|
||||||
|
|
||||||
/* =============================================================== */
|
/* =============================================================== */
|
||||||
@ -365,8 +360,8 @@ static const char * _numeric_error_strings[] =
|
|||||||
"No error",
|
"No error",
|
||||||
"Argument is not a valid number",
|
"Argument is not a valid number",
|
||||||
"Intermediate result overflow",
|
"Intermediate result overflow",
|
||||||
"Argument denominators differ in GNC_DENOM_FIXED operation",
|
"Argument denominators differ in GNC_HOW_DENOM_FIXED operation",
|
||||||
"Remainder part in GNC_RND_NEVER operation"
|
"Remainder part in GNC_HOW_RND_NEVER operation"
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -606,7 +601,7 @@ gnc_numeric_add(gnc_numeric a, gnc_numeric b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if((denom == GNC_DENOM_AUTO) &&
|
if((denom == GNC_DENOM_AUTO) &&
|
||||||
(how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED)
|
(how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED)
|
||||||
{
|
{
|
||||||
if(a.denom == b.denom) {
|
if(a.denom == b.denom) {
|
||||||
denom = a.denom;
|
denom = a.denom;
|
||||||
@ -668,7 +663,7 @@ gnc_numeric_add(gnc_numeric a, gnc_numeric b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if((denom == GNC_DENOM_AUTO) &&
|
if((denom == GNC_DENOM_AUTO) &&
|
||||||
((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD))
|
((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD))
|
||||||
{
|
{
|
||||||
denom = gnc_numeric_lcd(a, b);
|
denom = gnc_numeric_lcd(a, b);
|
||||||
how = how & GNC_NUMERIC_RND_MASK;
|
how = how & GNC_NUMERIC_RND_MASK;
|
||||||
@ -711,7 +706,7 @@ gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if((denom == GNC_DENOM_AUTO) &&
|
if((denom == GNC_DENOM_AUTO) &&
|
||||||
(how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED) {
|
(how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) {
|
||||||
if(a.denom == b.denom) {
|
if(a.denom == b.denom) {
|
||||||
denom = a.denom;
|
denom = a.denom;
|
||||||
}
|
}
|
||||||
@ -758,7 +753,7 @@ gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if((denom == GNC_DENOM_AUTO) &&
|
if((denom == GNC_DENOM_AUTO) &&
|
||||||
((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD))
|
((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD))
|
||||||
{
|
{
|
||||||
denom = gnc_numeric_lcd(a, b);
|
denom = gnc_numeric_lcd(a, b);
|
||||||
how = how & GNC_NUMERIC_RND_MASK;
|
how = how & GNC_NUMERIC_RND_MASK;
|
||||||
@ -785,7 +780,7 @@ gnc_numeric_div(gnc_numeric a, gnc_numeric b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if((denom == GNC_DENOM_AUTO) &&
|
if((denom == GNC_DENOM_AUTO) &&
|
||||||
(how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED)
|
(how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED)
|
||||||
{
|
{
|
||||||
if(a.denom == b.denom)
|
if(a.denom == b.denom)
|
||||||
{
|
{
|
||||||
@ -880,7 +875,7 @@ gnc_numeric_div(gnc_numeric a, gnc_numeric b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if((denom == GNC_DENOM_AUTO) &&
|
if((denom == GNC_DENOM_AUTO) &&
|
||||||
((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD))
|
((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD))
|
||||||
{
|
{
|
||||||
denom = gnc_numeric_lcd(a, b);
|
denom = gnc_numeric_lcd(a, b);
|
||||||
how = how & GNC_NUMERIC_RND_MASK;
|
how = how & GNC_NUMERIC_RND_MASK;
|
||||||
@ -942,17 +937,17 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
|
|||||||
switch(how & GNC_NUMERIC_DENOM_MASK)
|
switch(how & GNC_NUMERIC_DENOM_MASK)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case GNC_DENOM_LCD: /* LCD is meaningless with AUTO in here */
|
case GNC_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */
|
||||||
case GNC_DENOM_EXACT:
|
case GNC_HOW_DENOM_EXACT:
|
||||||
return in;
|
return in;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_DENOM_REDUCE:
|
case GNC_HOW_DENOM_REDUCE:
|
||||||
/* reduce the input to a relatively-prime fraction */
|
/* reduce the input to a relatively-prime fraction */
|
||||||
return gnc_numeric_reduce(in);
|
return gnc_numeric_reduce(in);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_DENOM_FIXED:
|
case GNC_HOW_DENOM_FIXED:
|
||||||
if(in.denom != denom) {
|
if(in.denom != denom) {
|
||||||
return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
|
return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
|
||||||
}
|
}
|
||||||
@ -961,7 +956,7 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_DENOM_SIGFIG:
|
case GNC_HOW_DENOM_SIGFIG:
|
||||||
ratio = fabs(gnc_numeric_to_double(in));
|
ratio = fabs(gnc_numeric_to_double(in));
|
||||||
if(ratio < 10e-20) {
|
if(ratio < 10e-20) {
|
||||||
logratio = 0;
|
logratio = 0;
|
||||||
@ -971,7 +966,7 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
|
|||||||
logratio = ((logratio > 0.0) ?
|
logratio = ((logratio > 0.0) ?
|
||||||
(floor(logratio)+1.0) : (ceil(logratio)));
|
(floor(logratio)+1.0) : (ceil(logratio)));
|
||||||
}
|
}
|
||||||
sigfigs = GNC_NUMERIC_GET_SIGFIGS(how);
|
sigfigs = GNC_HOW_GET_SIGFIGS(how);
|
||||||
|
|
||||||
if(sigfigs-logratio >= 0) {
|
if(sigfigs-logratio >= 0) {
|
||||||
denom = (gint64)(pow(10, sigfigs-logratio));
|
denom = (gint64)(pow(10, sigfigs-logratio));
|
||||||
@ -980,7 +975,7 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
|
|||||||
denom = -((gint64)(pow(10, logratio-sigfigs)));
|
denom = -((gint64)(pow(10, logratio-sigfigs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
how = how & ~GNC_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
|
how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1030,26 +1025,26 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
|
|||||||
if(remainder > 0)
|
if(remainder > 0)
|
||||||
{
|
{
|
||||||
switch(how) {
|
switch(how) {
|
||||||
case GNC_RND_FLOOR:
|
case GNC_HOW_RND_FLOOR:
|
||||||
if(sign < 0) {
|
if(sign < 0) {
|
||||||
out.num = out.num + 1;
|
out.num = out.num + 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_CEIL:
|
case GNC_HOW_RND_CEIL:
|
||||||
if(sign > 0) {
|
if(sign > 0) {
|
||||||
out.num = out.num + 1;
|
out.num = out.num + 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_TRUNC:
|
case GNC_HOW_RND_TRUNC:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_PROMOTE:
|
case GNC_HOW_RND_PROMOTE:
|
||||||
out.num = out.num + 1;
|
out.num = out.num + 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_ROUND_HALF_DOWN:
|
case GNC_HOW_RND_ROUND_HALF_DOWN:
|
||||||
if(denom_neg) {
|
if(denom_neg) {
|
||||||
if((2 * remainder) > in.denom*denom) {
|
if((2 * remainder) > in.denom*denom) {
|
||||||
out.num = out.num + 1;
|
out.num = out.num + 1;
|
||||||
@ -1060,7 +1055,7 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_ROUND_HALF_UP:
|
case GNC_HOW_RND_ROUND_HALF_UP:
|
||||||
if(denom_neg) {
|
if(denom_neg) {
|
||||||
if((2 * remainder) >= in.denom*denom) {
|
if((2 * remainder) >= in.denom*denom) {
|
||||||
out.num = out.num + 1;
|
out.num = out.num + 1;
|
||||||
@ -1071,7 +1066,7 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_ROUND:
|
case GNC_HOW_RND_ROUND:
|
||||||
if(denom_neg) {
|
if(denom_neg) {
|
||||||
if((2 * remainder) > in.denom*denom) {
|
if((2 * remainder) > in.denom*denom) {
|
||||||
out.num = out.num + 1;
|
out.num = out.num + 1;
|
||||||
@ -1094,7 +1089,7 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_NEVER:
|
case GNC_HOW_RND_NEVER:
|
||||||
return gnc_numeric_error(GNC_ERROR_REMAINDER);
|
return gnc_numeric_error(GNC_ERROR_REMAINDER);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1108,7 +1103,7 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
|
|||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
** reduce a fraction by GCF elimination. This is NOT done as a
|
** reduce a fraction by GCF elimination. This is NOT done as a
|
||||||
* part of the arithmetic API unless GNC_DENOM_REDUCE is specified
|
* part of the arithmetic API unless GNC_HOW_DENOM_REDUCE is specified
|
||||||
* as the output denominator.
|
* as the output denominator.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
@ -1154,7 +1149,8 @@ double_to_gnc_numeric(double in, gint64 denom, gint how)
|
|||||||
double logval;
|
double logval;
|
||||||
double sigfigs;
|
double sigfigs;
|
||||||
|
|
||||||
if((denom == GNC_DENOM_AUTO) && (how & GNC_DENOM_SIGFIG)) {
|
if((denom == GNC_DENOM_AUTO) && (how & GNC_HOW_DENOM_SIGFIG))
|
||||||
|
{
|
||||||
if(fabs(in) < 10e-20) {
|
if(fabs(in) < 10e-20) {
|
||||||
logval = 0;
|
logval = 0;
|
||||||
}
|
}
|
||||||
@ -1163,7 +1159,7 @@ double_to_gnc_numeric(double in, gint64 denom, gint how)
|
|||||||
logval = ((logval > 0.0) ?
|
logval = ((logval > 0.0) ?
|
||||||
(floor(logval)+1.0) : (ceil(logval)));
|
(floor(logval)+1.0) : (ceil(logval)));
|
||||||
}
|
}
|
||||||
sigfigs = GNC_NUMERIC_GET_SIGFIGS(how);
|
sigfigs = GNC_HOW_GET_SIGFIGS(how);
|
||||||
if(sigfigs-logval >= 0) {
|
if(sigfigs-logval >= 0) {
|
||||||
denom = (gint64)(pow(10, sigfigs-logval));
|
denom = (gint64)(pow(10, sigfigs-logval));
|
||||||
}
|
}
|
||||||
@ -1171,7 +1167,7 @@ double_to_gnc_numeric(double in, gint64 denom, gint how)
|
|||||||
denom = -((gint64)(pow(10, logval-sigfigs)));
|
denom = -((gint64)(pow(10, logval-sigfigs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
how = how & ~GNC_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
|
how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int_part = (gint64)(floor(fabs(in)));
|
int_part = (gint64)(floor(fabs(in)));
|
||||||
@ -1181,24 +1177,24 @@ double_to_gnc_numeric(double in, gint64 denom, gint how)
|
|||||||
frac_part = frac_part * (double)denom;
|
frac_part = frac_part * (double)denom;
|
||||||
|
|
||||||
switch(how & GNC_NUMERIC_RND_MASK) {
|
switch(how & GNC_NUMERIC_RND_MASK) {
|
||||||
case GNC_RND_FLOOR:
|
case GNC_HOW_RND_FLOOR:
|
||||||
frac_int = (gint64)floor(frac_part);
|
frac_int = (gint64)floor(frac_part);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_CEIL:
|
case GNC_HOW_RND_CEIL:
|
||||||
frac_int = (gint64)ceil(frac_part);
|
frac_int = (gint64)ceil(frac_part);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_TRUNC:
|
case GNC_HOW_RND_TRUNC:
|
||||||
frac_int = (gint64)frac_part;
|
frac_int = (gint64)frac_part;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_ROUND:
|
case GNC_HOW_RND_ROUND:
|
||||||
case GNC_RND_ROUND_HALF_UP:
|
case GNC_HOW_RND_ROUND_HALF_UP:
|
||||||
frac_int = (gint64)rint(frac_part);
|
frac_int = (gint64)rint(frac_part);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GNC_RND_NEVER:
|
case GNC_HOW_RND_NEVER:
|
||||||
frac_int = (gint64)floor(frac_part);
|
frac_int = (gint64)floor(frac_part);
|
||||||
if(frac_part != (double) frac_int) {
|
if(frac_part != (double) frac_int) {
|
||||||
/* signal an error */
|
/* signal an error */
|
||||||
@ -1226,21 +1222,6 @@ gnc_numeric_to_double(gnc_numeric in)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* gnc_numeric_create
|
|
||||||
********************************************************************/
|
|
||||||
|
|
||||||
gnc_numeric
|
|
||||||
gnc_numeric_create(gint64 num, gint64 denom)
|
|
||||||
{
|
|
||||||
gnc_numeric out;
|
|
||||||
out.num = num;
|
|
||||||
out.denom = denom;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* gnc_numeric_error
|
* gnc_numeric_error
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
@ -1252,39 +1233,6 @@ gnc_numeric_error(GNCNumericErrorCode error_code)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* gnc_numeric_zero
|
|
||||||
********************************************************************/
|
|
||||||
|
|
||||||
gnc_numeric
|
|
||||||
gnc_numeric_zero(void)
|
|
||||||
{
|
|
||||||
return gnc_numeric_create(0LL, 1LL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* gnc_numeric_num
|
|
||||||
********************************************************************/
|
|
||||||
|
|
||||||
gint64
|
|
||||||
gnc_numeric_num(gnc_numeric a)
|
|
||||||
{
|
|
||||||
return a.num;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* gnc_numeric_denom
|
|
||||||
********************************************************************/
|
|
||||||
|
|
||||||
gint64
|
|
||||||
gnc_numeric_denom(gnc_numeric a)
|
|
||||||
{
|
|
||||||
return a.denom;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* gnc_numeric_add_with_error
|
* gnc_numeric_add_with_error
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
@ -1297,9 +1245,9 @@ gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b,
|
|||||||
|
|
||||||
gnc_numeric sum = gnc_numeric_add(a, b, denom, how);
|
gnc_numeric sum = gnc_numeric_add(a, b, denom, how);
|
||||||
gnc_numeric exact = gnc_numeric_add(a, b, GNC_DENOM_AUTO,
|
gnc_numeric exact = gnc_numeric_add(a, b, GNC_DENOM_AUTO,
|
||||||
GNC_DENOM_REDUCE);
|
GNC_HOW_DENOM_REDUCE);
|
||||||
gnc_numeric err = gnc_numeric_sub(sum, exact, GNC_DENOM_AUTO,
|
gnc_numeric err = gnc_numeric_sub(sum, exact, GNC_DENOM_AUTO,
|
||||||
GNC_DENOM_REDUCE);
|
GNC_HOW_DENOM_REDUCE);
|
||||||
|
|
||||||
if(error) {
|
if(error) {
|
||||||
*error = err;
|
*error = err;
|
||||||
@ -1318,9 +1266,9 @@ gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
|
|||||||
{
|
{
|
||||||
gnc_numeric diff = gnc_numeric_sub(a, b, denom, how);
|
gnc_numeric diff = gnc_numeric_sub(a, b, denom, how);
|
||||||
gnc_numeric exact = gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
|
gnc_numeric exact = gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
|
||||||
GNC_DENOM_REDUCE);
|
GNC_HOW_DENOM_REDUCE);
|
||||||
gnc_numeric err = gnc_numeric_sub(diff, exact, GNC_DENOM_AUTO,
|
gnc_numeric err = gnc_numeric_sub(diff, exact, GNC_DENOM_AUTO,
|
||||||
GNC_DENOM_REDUCE);
|
GNC_HOW_DENOM_REDUCE);
|
||||||
if(error) {
|
if(error) {
|
||||||
*error = err;
|
*error = err;
|
||||||
}
|
}
|
||||||
@ -1339,9 +1287,9 @@ gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b,
|
|||||||
{
|
{
|
||||||
gnc_numeric prod = gnc_numeric_mul(a, b, denom, how);
|
gnc_numeric prod = gnc_numeric_mul(a, b, denom, how);
|
||||||
gnc_numeric exact = gnc_numeric_mul(a, b, GNC_DENOM_AUTO,
|
gnc_numeric exact = gnc_numeric_mul(a, b, GNC_DENOM_AUTO,
|
||||||
GNC_DENOM_REDUCE);
|
GNC_HOW_DENOM_REDUCE);
|
||||||
gnc_numeric err = gnc_numeric_sub(prod, exact, GNC_DENOM_AUTO,
|
gnc_numeric err = gnc_numeric_sub(prod, exact, GNC_DENOM_AUTO,
|
||||||
GNC_DENOM_REDUCE);
|
GNC_HOW_DENOM_REDUCE);
|
||||||
if(error) {
|
if(error) {
|
||||||
*error = err;
|
*error = err;
|
||||||
}
|
}
|
||||||
@ -1360,9 +1308,9 @@ gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
|
|||||||
{
|
{
|
||||||
gnc_numeric quot = gnc_numeric_div(a, b, denom, how);
|
gnc_numeric quot = gnc_numeric_div(a, b, denom, how);
|
||||||
gnc_numeric exact = gnc_numeric_div(a, b, GNC_DENOM_AUTO,
|
gnc_numeric exact = gnc_numeric_div(a, b, GNC_DENOM_AUTO,
|
||||||
GNC_DENOM_REDUCE);
|
GNC_HOW_DENOM_REDUCE);
|
||||||
gnc_numeric err = gnc_numeric_sub(quot, exact,
|
gnc_numeric err = gnc_numeric_sub(quot, exact,
|
||||||
GNC_DENOM_AUTO, GNC_DENOM_REDUCE);
|
GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
|
||||||
if(error) {
|
if(error) {
|
||||||
*error = err;
|
*error = err;
|
||||||
}
|
}
|
||||||
@ -1444,25 +1392,25 @@ main(int argc, char ** argv)
|
|||||||
|
|
||||||
gnc_numeric err;
|
gnc_numeric err;
|
||||||
|
|
||||||
c = gnc_numeric_add_with_error(a, b, 100, GNC_RND_ROUND, &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",
|
printf("add 100ths/error : %s + %s = %s + (error) %s\n\n",
|
||||||
gnc_numeric_print(a), gnc_numeric_print(b),
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
||||||
gnc_numeric_print(c),
|
gnc_numeric_print(c),
|
||||||
gnc_numeric_print(err));
|
gnc_numeric_print(err));
|
||||||
|
|
||||||
c = gnc_numeric_sub_with_error(a, b, 100, GNC_RND_FLOOR, &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",
|
printf("sub 100ths/error : %s - %s = %s + (error) %s\n\n",
|
||||||
gnc_numeric_print(a), gnc_numeric_print(b),
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
||||||
gnc_numeric_print(c),
|
gnc_numeric_print(c),
|
||||||
gnc_numeric_print(err));
|
gnc_numeric_print(err));
|
||||||
|
|
||||||
c = gnc_numeric_mul_with_error(a, b, 100, GNC_RND_ROUND, &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",
|
printf("mul 100ths/error : %s * %s = %s + (error) %s\n\n",
|
||||||
gnc_numeric_print(a), gnc_numeric_print(b),
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
||||||
gnc_numeric_print(c),
|
gnc_numeric_print(c),
|
||||||
gnc_numeric_print(err));
|
gnc_numeric_print(err));
|
||||||
|
|
||||||
c = gnc_numeric_div_with_error(a, b, 100, GNC_RND_ROUND, &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",
|
printf("div 100ths/error : %s / %s = %s + (error) %s\n\n",
|
||||||
gnc_numeric_print(a), gnc_numeric_print(b),
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
||||||
gnc_numeric_print(c),
|
gnc_numeric_print(c),
|
||||||
@ -1470,11 +1418,11 @@ main(int argc, char ** argv)
|
|||||||
|
|
||||||
printf("multiply (EXACT): %s * %s = %s\n",
|
printf("multiply (EXACT): %s * %s = %s\n",
|
||||||
gnc_numeric_print(a), gnc_numeric_print(b),
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
||||||
gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT)));
|
gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT)));
|
||||||
|
|
||||||
printf("multiply (REDUCE): %s * %s = %s\n",
|
printf("multiply (REDUCE): %s * %s = %s\n",
|
||||||
gnc_numeric_print(a), gnc_numeric_print(b),
|
gnc_numeric_print(a), gnc_numeric_print(b),
|
||||||
gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_REDUCE)));
|
gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE)));
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -42,204 +42,10 @@
|
|||||||
@author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
|
@author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if JUNK
|
/** ----------------------------------------------------------
|
||||||
|
|
||||||
/*******************
|
|
||||||
@menu
|
|
||||||
* Standard Numeric Arguments::
|
|
||||||
* Creating Numeric Objects::
|
|
||||||
* Basic Arithmetic Operations::
|
|
||||||
* Numeric Comparisons and Predicates::
|
|
||||||
* Numeric Denominator Conversion::
|
|
||||||
* Numeric Floating Point Conversion::
|
|
||||||
* Numeric String Conversion::
|
|
||||||
* Numeric Error Handling ::
|
|
||||||
* Numeric Example::
|
|
||||||
@end menu
|
|
||||||
|
|
||||||
@node Standard Numeric Arguments, Creating Numeric Objects, Numeric Library, Numeric Library
|
|
||||||
@subsection Standard Numeric Arguments
|
|
||||||
@cindex Standard Numeric Arguments
|
|
||||||
|
|
||||||
It is useful to specify a denominator in cases where it is known that
|
|
||||||
the output value is of constrained precision. For example, monetary
|
|
||||||
transactions must be executed in an integer number of the "smallest
|
|
||||||
currency unit" of the transaction. In US Dollars, the smallest currency
|
|
||||||
unit is the cent, and all monetary transactions must be done in units of
|
|
||||||
cents. Therefore, any fractional cents in a computed price must be
|
|
||||||
rounded away.
|
|
||||||
|
|
||||||
Most of the @code{gnc_numeric} arithmetic functions take two arguments
|
|
||||||
in addition to their numeric args: @var{denom}, which is the denominator
|
|
||||||
to use in the output @code{gnc_numeric object}, and @var{how}, which
|
|
||||||
describes how the arithmetic result is to be converted to that
|
|
||||||
denominator. This combination of output denominator and rounding policy
|
|
||||||
allows the results of financial and other exact computations to be
|
|
||||||
properly rounded to the appropriate units.
|
|
||||||
|
|
||||||
Valid values for @var{denom} are:
|
|
||||||
|
|
||||||
Valid values for @var{how} are bitwise combinations of zero or one
|
|
||||||
"rounding instructions" with zero or one "denominator types".
|
|
||||||
|
|
||||||
The denominator type specifies how to compute a denominator if
|
|
||||||
@code{GNC_DENOM_AUTO} is specified as the @var{denom}. Valid denominator
|
|
||||||
types are:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
To use traditional rational-number operational semantics (all results
|
|
||||||
are exact and are reduced to relatively-prime fractions) pass the
|
|
||||||
argument @code{GNC_DENOM_AUTO} as @var{denom} and @code{GNC_DENOM_REDUCE
|
|
||||||
| GNC_RND_NEVER} as @var{how}.
|
|
||||||
|
|
||||||
To enforce strict financial semantics (such that all operands must have
|
|
||||||
the same denominator as each other and as the result), use
|
|
||||||
@var{GNC_DENOM_AUTO} as @var{denom} and @code{GNC_DENOM_FIXED |
|
|
||||||
GNC_RND_NEVER} as @var{how}.
|
|
||||||
|
|
||||||
|
|
||||||
@node Creating Numeric Objects, Basic Arithmetic Operations, Standard Numeric Arguments, Numeric Library
|
|
||||||
@subsection Creating Numeric Objects
|
|
||||||
@cindex Creating Numeric Objects
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_create (int @var{num}, int @var{denom})
|
|
||||||
Create a @code{gnc_numeric} object with a value of "@var{num} / @var{denom}".
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_zero ()
|
|
||||||
Create a @code{gnc_numeric} object with a value of 0.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
|
|
||||||
@node Basic Arithmetic Operations, Numeric Comparisons and Predicates, Creating Numeric Objects, Numeric Library
|
|
||||||
@subsection Basic Arithmetic Operations
|
|
||||||
@cindex Basic Arithmetic Operations
|
|
||||||
|
|
||||||
See @ref{Standard Numeric Arguments} for a description of the @var{denom}
|
|
||||||
and @var{how} arguments to each arithmetic function.
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_add (gnc_numeric @var{a}, gnc_numeric @var{b}, gint64 @var{denom}, gint @var{how})
|
|
||||||
Return the sum of @var{a} and @var{b}.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_sub (gnc_numeric @var{a}, gnc_numeric @var{b}, gint64 @var{denom}, gint @var{how})
|
|
||||||
Return "@var{a} - @var{b}".
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_div (gnc_numeric @var{a}, gnc_numeric @var{b}, gint64 @var{denom}, gint @var{how})
|
|
||||||
Return "@var{a} / @var{b}".
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_add_with_error (gnc_numeric @var{a}, gnc_numeric @var{b}, gint64 @var{denom}, gint @var{how}, {gnc_numeric *} @var{error})
|
|
||||||
The same as @code{gnc_numeric_add}, but uses @var{error} for accumulating
|
|
||||||
conversion roundoff error.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_sub_with_error (gnc_numeric @var{a}, gnc_numeric @var{b}, gint64 @var{denom}, gint @var{how}, {gnc_numeric *} @var{error})
|
|
||||||
The same as @code{gnc_numeric_sub}, but uses @var{error} for accumulating
|
|
||||||
conversion roundoff error.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_div_with_error (gnc_numeric @var{a}, gnc_numeric @var{b}, gint64 @var{denom}, gint @var{how}, {gnc_numeric *} @var{error})
|
|
||||||
The same as @code{gnc_numeric_div}, but uses @var{error} for accumulating
|
|
||||||
conversion roundoff error.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
|
|
||||||
@node Numeric Comparisons and Predicates, Numeric Denominator Conversion, Basic Arithmetic Operations, Numeric Library
|
|
||||||
@subsection Numeric Comparisons and Predicates
|
|
||||||
@cindex Numeric Comparisons and Predicates
|
|
||||||
|
|
||||||
@deftypefun int gnc_numeric_compare (gnc_numeric @var{a}, gnc_numeric @var{b})
|
|
||||||
Returns +1 if @code{@var{a} > @var{b}}, -1 if @code{@var{b} > @var{a}}, 0 if @code{@var{a} == @var{b}}.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun int gnc_numeric_eq (gnc_numeric @var{a}, gnc_numeric @var{b})
|
|
||||||
Returns 1 if @code{numerator(@var{a}) == numerator(@var{b})} and
|
|
||||||
@code{denominator(@var{a}) == denominator(@var{b})}, otherwise returns 0.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun int gnc_numeric_equal (gnc_numeric @var{a}, gnc_numeric @var{b})
|
|
||||||
Returns 1 if the fraction represented by @var{a} is equal to the fraction
|
|
||||||
represented by @var{b}, otherwise returns 0.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun int gnc_numeric_same (gnc_numeric @var{a}, gnc_numeric @var{b}, gint64 @var{denom}, gint @var{how})
|
|
||||||
Convert both @var{a} and @var{b} to @var{denom} (@pxref{Standard Numeric
|
|
||||||
Arguments} and compare numerators of the result.
|
|
||||||
|
|
||||||
@example
|
|
||||||
For example, if @code{@var{a} == 7/16} and @code{@var{b} == 3/4},
|
|
||||||
@code{gnc_numeric_same(@var{a}, @var{b}, 2, GNC_RND_TRUNC) == 1}
|
|
||||||
because both 7/16 and 3/4 round to 1/2 under truncation. However,
|
|
||||||
@code{gnc_numeric_same(@var{a}, @var{b}, 2, GNC_RND_ROUND) == 0}
|
|
||||||
because 7/16 rounds to 1/2 under unbiased rounding but 3/4 rounds
|
|
||||||
to 2/2.
|
|
||||||
@end example
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
|
|
||||||
@node Numeric Denominator Conversion, Numeric Floating Point Conversion, Numeric Comparisons and Predicates, Numeric Library
|
|
||||||
@subsection Numeric Denominator Conversion
|
|
||||||
@cindex Numeric Denominator Conversion
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_convert (gnc_numeric @var{in}, gint64 @var{denom}, gint @var{how})
|
|
||||||
Convert @var{in} to the specified denominator under standard arguments
|
|
||||||
@var{denom} and @var{how}. @xref{Standard Numeric Arguments}.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_convert_with_error (gnc_numeric @var{in}, gint64 @var{denom}, gint @var{how}, {gnc_numeric *} @var{error})
|
|
||||||
Same as @code{gnc_numeric_convert}, but return a remainder value for
|
|
||||||
accumulating conversion error.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@node Numeric Floating Point Conversion, Numeric String Conversion, Numeric Denominator Conversion, Numeric Library
|
|
||||||
@subsection Numeric Floating Point Conversion
|
|
||||||
@cindex Numeric Floating Point Conversion
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric double_to_gnc_numeric (double @var{arg}, gint64 @var{denom}, gint @var{how})
|
|
||||||
Convert a floating-point number to a @code{gnc_numeric}. Both @var{denom}
|
|
||||||
and @var{how} are used as in arithmetic, but @code{GNC_DENOM_AUTO} is
|
|
||||||
not recognized.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun double gnc_numeric_to_double (gnc_numeric @var{arg})
|
|
||||||
Convert @var{arg} to a @code{double} value.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
|
|
||||||
@node Numeric String Conversion, Numeric Error Handling , Numeric Floating Point Conversion, Numeric Library
|
|
||||||
@subsection Numeric String Conversion
|
|
||||||
@cindex Numeric String Conversion
|
|
||||||
|
|
||||||
@deftypefun {gchar *} gnc_numeric_to_string (gnc_numeric @var{n})
|
|
||||||
Return a string representation of @var{n}. The string must be
|
|
||||||
freed with @code{g_free}.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
@deftypefun {const gchar *} string_to_gnc_numeric (const {gchar *} @var{str}, {gnc_numeric *} @var{n})
|
|
||||||
Read a @code{gnc_numeric} from @var{str}, skipping any leading
|
|
||||||
whitespace, and returning a pointer to just past the last byte
|
|
||||||
read. Return NULL on error.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
|
|
||||||
@node Numeric Error Handling , Numeric Example, Numeric String Conversion, Numeric Library
|
|
||||||
@subsection Numeric Error Handling
|
|
||||||
@cindex Numeric Error Handling
|
|
||||||
|
|
||||||
|
|
||||||
@deftypefun gnc_numeric gnc_numeric_error (int error_code)
|
|
||||||
Create a @code{gnc_numeric} object that signals the error condition
|
|
||||||
noted by @var{error_code} rather than a number.
|
|
||||||
@end deftypefun
|
|
||||||
|
|
||||||
|
|
||||||
@node Numeric Example, , Numeric Error Handling , Numeric Library
|
|
||||||
@subsection Numeric Example
|
|
||||||
@cindex Numeric Example
|
|
||||||
|
|
||||||
|
EXAMPLE
|
||||||
|
-------
|
||||||
The following program finds the best @code{gnc_numeric} approximation to
|
The following program finds the best @code{gnc_numeric} approximation to
|
||||||
the @file{math.h} constant @code{M_PI} given a maximum denominator. For
|
the @file{math.h} constant @code{M_PI} given a maximum denominator. For
|
||||||
large denominators, the @code{gnc_numeric} approximation is accurate to
|
large denominators, the @code{gnc_numeric} approximation is accurate to
|
||||||
@ -260,7 +66,7 @@ this may not be good enough. For example,
|
|||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char ** argv)
|
main(int argc, char ** argv)
|
||||||
@{
|
{
|
||||||
gnc_numeric approx, best;
|
gnc_numeric approx, best;
|
||||||
double err, best_err=1.0;
|
double err, best_err=1.0;
|
||||||
double m_pi = M_PI;
|
double m_pi = M_PI;
|
||||||
@ -270,43 +76,90 @@ main(int argc, char ** argv)
|
|||||||
sscanf(argv[1], "%Ld", &max);
|
sscanf(argv[1], "%Ld", &max);
|
||||||
|
|
||||||
for (denom = 1; denom < max; denom++)
|
for (denom = 1; denom < max; denom++)
|
||||||
@{
|
{
|
||||||
approx = double_to_gnc_numeric (m_pi, denom, GNC_RND_ROUND);
|
approx = double_to_gnc_numeric (m_pi, denom, GNC_RND_ROUND);
|
||||||
err = m_pi - gnc_numeric_to_double (approx);
|
err = m_pi - gnc_numeric_to_double (approx);
|
||||||
if (fabs (err) < fabs (best_err))
|
if (fabs (err) < fabs (best_err))
|
||||||
@{
|
{
|
||||||
best = approx;
|
best = approx;
|
||||||
best_err = err;
|
best_err = err;
|
||||||
printf ("%Ld / %Ld = %.30f\n", gnc_numeric_num (best),
|
printf ("%Ld / %Ld = %.30f\n", gnc_numeric_num (best),
|
||||||
gnc_numeric_denom (best), gnc_numeric_to_double (best));
|
gnc_numeric_denom (best), gnc_numeric_to_double (best));
|
||||||
@}
|
}
|
||||||
@}
|
}
|
||||||
@}
|
}
|
||||||
@end example
|
|
||||||
|
|
||||||
**********************/
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------- */
|
||||||
|
|
||||||
#ifndef GNC_NUMERIC_H
|
#ifndef GNC_NUMERIC_H
|
||||||
#define GNC_NUMERIC_H
|
#define GNC_NUMERIC_H
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
struct _gnc_numeric {
|
struct _gnc_numeric
|
||||||
|
{
|
||||||
gint64 num;
|
gint64 num;
|
||||||
gint64 denom;
|
gint64 denom;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @brief An exact-number type
|
/** @brief An rational-number type
|
||||||
*
|
*
|
||||||
* This is a rational number, defined by nominator and denominator. */
|
* This is a rational number, defined by numerator and denominator. */
|
||||||
typedef struct _gnc_numeric gnc_numeric;
|
typedef struct _gnc_numeric gnc_numeric;
|
||||||
|
|
||||||
|
/** @name Arguments
|
||||||
|
* @brief Standard Arguments to most functions
|
||||||
|
|
||||||
|
Most of the gnc_numeric arithmetic functions take two arguments
|
||||||
|
in addition to their numeric args: @var{denom}, which is the denominator
|
||||||
|
to use in the output @code{gnc_numeric object}, and @var{how}, which
|
||||||
|
describes how the arithmetic result is to be converted to that
|
||||||
|
denominator. This combination of output denominator and rounding policy
|
||||||
|
allows the results of financial and other rational computations to be
|
||||||
|
properly rounded to the appropriate units.
|
||||||
|
|
||||||
|
Valid values for @var{denom} are:
|
||||||
|
GNC_DENOM_AUTO -- compute denominator exactly
|
||||||
|
integer n -- Force the denominator of teh result to be this integer
|
||||||
|
GNC_DENOM_RECIPROCAL -- Use 1/n as the denominator (???huh???)
|
||||||
|
|
||||||
|
Valid values for @var{how} are bitwise combinations of zero or one
|
||||||
|
"rounding instructions" with zero or one "denominator types".
|
||||||
|
Valid rounding instructions are:
|
||||||
|
GNC_HOW_RND_FLOOR
|
||||||
|
GNC_HOW_RND_CEIL
|
||||||
|
GNC_HOW_RND_TRUNC
|
||||||
|
GNC_HOW_RND_PROMOTE
|
||||||
|
GNC_HOW_RND_ROUND_HALF_DOWN
|
||||||
|
GNC_HOW_RND_ROUND_HALF_UP
|
||||||
|
GNC_HOW_RND_ROUND
|
||||||
|
GNC_HOW_RND_NEVER
|
||||||
|
|
||||||
|
The denominator type specifies how to compute a denominator if
|
||||||
|
@code{GNC_DENOM_AUTO} is specified as the @var{denom}. Valid
|
||||||
|
denominator types are:
|
||||||
|
GNC_HOW_DENOM_EXACT
|
||||||
|
GNC_HOW_DENOM_REDUCE
|
||||||
|
GNC_HOW_DENOM_LCD
|
||||||
|
GNC_HOW_DENOM_FIXED
|
||||||
|
GNC_HOW_DENOM_SIGFIGS(N)
|
||||||
|
|
||||||
|
To use traditional rational-number operational semantics (all results
|
||||||
|
are exact and are reduced to relatively-prime fractions) pass the
|
||||||
|
argument @code{GNC_DENOM_AUTO} as @var{denom} and
|
||||||
|
@code{GNC_HOW_DENOM_REDUCE| GNC_HOW_RND_NEVER} as @var{how}.
|
||||||
|
|
||||||
|
To enforce strict financial semantics (such that all operands must have
|
||||||
|
the same denominator as each other and as the result), use
|
||||||
|
@var{GNC_DENOM_AUTO} as @var{denom} and
|
||||||
|
@code{GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER} as @var{how}.
|
||||||
|
|
||||||
|
@{ */
|
||||||
|
|
||||||
/** bitmasks for HOW flags.
|
/** bitmasks for HOW flags.
|
||||||
* bits 8-15 of 'how' are reserved for the number of significant
|
* bits 8-15 of 'how' are reserved for the number of significant
|
||||||
* digits to use in the output with GNC_DENOM_SIGFIG */
|
* digits to use in the output with GNC_HOW_DENOM_SIGFIG
|
||||||
|
*/
|
||||||
#define GNC_NUMERIC_RND_MASK 0x0000000f
|
#define GNC_NUMERIC_RND_MASK 0x0000000f
|
||||||
#define GNC_NUMERIC_DENOM_MASK 0x000000f0
|
#define GNC_NUMERIC_DENOM_MASK 0x000000f0
|
||||||
#define GNC_NUMERIC_SIGFIGS_MASK 0x0000ff00
|
#define GNC_NUMERIC_SIGFIGS_MASK 0x0000ff00
|
||||||
@ -321,38 +174,38 @@ typedef struct _gnc_numeric gnc_numeric;
|
|||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
/** Round toward -infinity */
|
/** Round toward -infinity */
|
||||||
GNC_RND_FLOOR = 0x01,
|
GNC_HOW_RND_FLOOR = 0x01,
|
||||||
|
|
||||||
/** Round toward +infinity */
|
/** Round toward +infinity */
|
||||||
GNC_RND_CEIL = 0x02,
|
GNC_HOW_RND_CEIL = 0x02,
|
||||||
|
|
||||||
/** Truncate fractions (round toward zero) */
|
/** Truncate fractions (round toward zero) */
|
||||||
GNC_RND_TRUNC = 0x03,
|
GNC_HOW_RND_TRUNC = 0x03,
|
||||||
|
|
||||||
/** Promote fractions (round away from zero) */
|
/** Promote fractions (round away from zero) */
|
||||||
GNC_RND_PROMOTE = 0x04,
|
GNC_HOW_RND_PROMOTE = 0x04,
|
||||||
|
|
||||||
/** Round to the nearest integer, rounding toward zero
|
/** Round to the nearest integer, rounding toward zero
|
||||||
* when there are two equidistant nearest integers.
|
* when there are two equidistant nearest integers.
|
||||||
*/
|
*/
|
||||||
GNC_RND_ROUND_HALF_DOWN = 0x05,
|
GNC_HOW_RND_ROUND_HALF_DOWN = 0x05,
|
||||||
|
|
||||||
/** Round to the nearest integer, rounding away from zero
|
/** Round to the nearest integer, rounding away from zero
|
||||||
* when there are two equidistant nearest integers.
|
* when there are two equidistant nearest integers.
|
||||||
*/
|
*/
|
||||||
GNC_RND_ROUND_HALF_UP = 0x06,
|
GNC_HOW_RND_ROUND_HALF_UP = 0x06,
|
||||||
|
|
||||||
/** Use unbiased ("banker's") rounding. This rounds to the
|
/** Use unbiased ("banker's") rounding. This rounds to the
|
||||||
* nearest integer, and to the nearest even integer when there
|
* nearest integer, and to the nearest even integer when there
|
||||||
* are two equidistant nearest integers. This is generally the
|
* are two equidistant nearest integers. This is generally the
|
||||||
* one you should use for financial quantities.
|
* one you should use for financial quantities.
|
||||||
*/
|
*/
|
||||||
GNC_RND_ROUND = 0x07,
|
GNC_HOW_RND_ROUND = 0x07,
|
||||||
|
|
||||||
/** Never round at all, and signal an error if there is a
|
/** Never round at all, and signal an error if there is a
|
||||||
* fractional result in a computation.
|
* fractional result in a computation.
|
||||||
*/
|
*/
|
||||||
GNC_RND_NEVER = 0x08
|
GNC_HOW_RND_NEVER = 0x08
|
||||||
};
|
};
|
||||||
|
|
||||||
/** How to compute a denominator, or'ed into the "how" field. */
|
/** How to compute a denominator, or'ed into the "how" field. */
|
||||||
@ -362,42 +215,48 @@ enum {
|
|||||||
* lose any information in the result but also do not want to
|
* lose any information in the result but also do not want to
|
||||||
* spend any time finding the "best" denominator.
|
* spend any time finding the "best" denominator.
|
||||||
*/
|
*/
|
||||||
GNC_DENOM_EXACT = 0x10,
|
GNC_HOW_DENOM_EXACT = 0x10,
|
||||||
|
|
||||||
/** Reduce the result value by common factor elimination,
|
/** Reduce the result value by common factor elimination,
|
||||||
* using the smallest possible value for the denominator that
|
* using the smallest possible value for the denominator that
|
||||||
* keeps the correct ratio. The numerator and denominator of
|
* keeps the correct ratio. The numerator and denominator of
|
||||||
* the result are relatively prime.
|
* the result are relatively prime.
|
||||||
*/
|
*/
|
||||||
GNC_DENOM_REDUCE = 0x20,
|
GNC_HOW_DENOM_REDUCE = 0x20,
|
||||||
|
|
||||||
/** Find the least common multiple of the arguments' denominators
|
/** Find the least common multiple of the arguments' denominators
|
||||||
* and use that as the denominator of the result.
|
* and use that as the denominator of the result.
|
||||||
*/
|
*/
|
||||||
GNC_DENOM_LCD = 0x30,
|
GNC_HOW_DENOM_LCD = 0x30,
|
||||||
|
|
||||||
/** All arguments are required to have the same denominator,
|
/** All arguments are required to have the same denominator,
|
||||||
* that denominator is to be used in the output, and an error
|
* that denominator is to be used in the output, and an error
|
||||||
* is to be signaled if any argument has a different denominator.
|
* is to be signaled if any argument has a different denominator.
|
||||||
*/
|
*/
|
||||||
GNC_DENOM_FIXED = 0x40,
|
GNC_HOW_DENOM_FIXED = 0x40,
|
||||||
|
|
||||||
/** Round to the number of significant figures given in the rounding
|
/** Round to the number of significant figures given in the rounding
|
||||||
* instructions by the GNC_DENOM_SIGFIGS () macro.
|
* instructions by the GNC_HOW_DENOM_SIGFIGS () macro.
|
||||||
*/
|
*/
|
||||||
GNC_DENOM_SIGFIG = 0x50
|
GNC_HOW_DENOM_SIGFIG = 0x50
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Build a 'how' value that will generate a denominator that will
|
||||||
|
* keep at least n significant figures in the result.
|
||||||
|
*/
|
||||||
|
#define GNC_HOW_DENOM_SIGFIGS( n ) ( ((( n ) & 0xff) << 8) | GNC_HOW_DENOM_SIGFIG)
|
||||||
|
#define GNC_HOW_GET_SIGFIGS( a ) ( (( a ) & 0xff00 ) >> 8)
|
||||||
|
|
||||||
/** Error codes */
|
/** Error codes */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GNC_ERROR_OK = 0, /**< No error */
|
GNC_ERROR_OK = 0, /**< No error */
|
||||||
GNC_ERROR_ARG = -1, /**< Argument is not a valid number */
|
GNC_ERROR_ARG = -1, /**< Argument is not a valid number */
|
||||||
GNC_ERROR_OVERFLOW = -2, /**< Intermediate result overflow */
|
GNC_ERROR_OVERFLOW = -2, /**< Intermediate result overflow */
|
||||||
|
|
||||||
/** GNC_DENOM_FIXED was specified, but argument denominators differed. */
|
/** GNC_HOW_DENOM_FIXED was specified, but argument denominators differed. */
|
||||||
GNC_ERROR_DENOM_DIFF = -3,
|
GNC_ERROR_DENOM_DIFF = -3,
|
||||||
|
|
||||||
/** GNC_RND_NEVER was specified, but the result could not be
|
/** GNC_HOW_RND_NEVER was specified, but the result could not be
|
||||||
* converted to the desired denominator without a remainder. */
|
* converted to the desired denominator without a remainder. */
|
||||||
GNC_ERROR_REMAINDER = -4
|
GNC_ERROR_REMAINDER = -4
|
||||||
} GNCNumericErrorCode;
|
} GNCNumericErrorCode;
|
||||||
@ -417,50 +276,61 @@ typedef enum {
|
|||||||
/** Use the value @code{1/n} as the denominator of the output value. */
|
/** Use the value @code{1/n} as the denominator of the output value. */
|
||||||
#define GNC_DENOM_RECIPROCAL( a ) (- ( a ))
|
#define GNC_DENOM_RECIPROCAL( a ) (- ( a ))
|
||||||
|
|
||||||
/** Use a value for the denominator that will keep at least n
|
/** @} */
|
||||||
* significant figures in the result.
|
|
||||||
*/
|
|
||||||
#define GNC_DENOM_SIGFIGS( n ) ( ((( n ) & 0xff) << 8) | GNC_DENOM_SIGFIG)
|
|
||||||
#define GNC_NUMERIC_GET_SIGFIGS( a ) ( (( a ) & 0xff00 ) >> 8)
|
|
||||||
|
|
||||||
/** @name Constructors */
|
/** @name Constructors
|
||||||
/*@{*/
|
@{*/
|
||||||
/** make a gnc_numeric from numerator and denominator */
|
/** Make a gnc_numeric from numerator and denominator */
|
||||||
gnc_numeric gnc_numeric_create(gint64 num, gint64 denom);
|
static inline
|
||||||
|
gnc_numeric gnc_numeric_create(gint64 num, gint64 denom) {
|
||||||
|
gnc_numeric out;
|
||||||
|
out.num = num;
|
||||||
|
out.denom = denom;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
/** create a zero-value gnc_numeric */
|
/** create a zero-value gnc_numeric */
|
||||||
gnc_numeric gnc_numeric_zero(void);
|
static inline
|
||||||
|
gnc_numeric gnc_numeric_zero(void) { return gnc_numeric_create(0, 1); }
|
||||||
|
|
||||||
/** convert from floating-point values */
|
/** Convert a floating-point number to a gnc_numeric.
|
||||||
|
* Both @var{denom} and @var{how} are used as in arithmetic,
|
||||||
|
* but @code{GNC_DENOM_AUTO} is not recognized; a denominator
|
||||||
|
* must be specified either explicitctly or through sigfigs.
|
||||||
|
*/
|
||||||
gnc_numeric double_to_gnc_numeric(double in, gint64 denom,
|
gnc_numeric double_to_gnc_numeric(double in, gint64 denom,
|
||||||
gint how);
|
gint how);
|
||||||
|
|
||||||
/** Read a gnc_numeric from str, skipping any leading whitespace, and
|
/** Read a gnc_numeric from str, skipping any leading whitespace,
|
||||||
returning a pointer to just past the last byte read. Return NULL
|
* and return a pointer to just past the last byte read.
|
||||||
on error. */
|
* Return NULL on error. */
|
||||||
const gchar *string_to_gnc_numeric(const gchar* str, gnc_numeric *n);
|
const gchar *string_to_gnc_numeric(const gchar* str, gnc_numeric *n);
|
||||||
|
|
||||||
/** make a special error-signalling gnc_numeric */
|
/** Create a gnc_numeric object that signals the error condition
|
||||||
|
* noted by @var{error_code}, rather than a number.
|
||||||
|
*/
|
||||||
gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code);
|
gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code);
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
/** @name Value accessors */
|
/** @name Value accessors */
|
||||||
/*@{*/
|
/** @{*/
|
||||||
/** Get parts */
|
/** Return numerator */
|
||||||
gint64 gnc_numeric_num(gnc_numeric a);
|
static inline
|
||||||
/** Get parts */
|
gint64 gnc_numeric_num(gnc_numeric a) { return a.num; }
|
||||||
gint64 gnc_numeric_denom(gnc_numeric a);
|
/** Return denominator */
|
||||||
|
static inline
|
||||||
|
gint64 gnc_numeric_denom(gnc_numeric a) { return a.denom; }
|
||||||
|
|
||||||
/** Convert to floating-point values */
|
/** Convert numeric to floating-point value. */
|
||||||
double gnc_numeric_to_double(gnc_numeric in);
|
double gnc_numeric_to_double(gnc_numeric in);
|
||||||
|
|
||||||
/** Convert to string. The returned buffer is to be g_free'd by the
|
/** Convert to string. The returned buffer is to be g_free'd by the
|
||||||
* caller (it was allocated through g_strdup) */
|
* caller (it was allocated through g_strdup) */
|
||||||
gchar *gnc_numeric_to_string(gnc_numeric n);
|
gchar *gnc_numeric_to_string(gnc_numeric n);
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
/** @name Tests */
|
/** @name Tests */
|
||||||
/*@{*/
|
/** @{*/
|
||||||
/** Check for error signal in value. Returns GNC_ERROR_OK (==0) if
|
/** Check for error signal in value. Returns GNC_ERROR_OK (==0) if
|
||||||
* the number appears to be valid, otherwise it returns the
|
* the number appears to be valid, otherwise it returns the
|
||||||
* type of error. Error values always have a denominator of zero.
|
* type of error. Error values always have a denominator of zero.
|
||||||
@ -479,29 +349,42 @@ gboolean gnc_numeric_negative_p(gnc_numeric a);
|
|||||||
/** Returns 1 if @var{a} > 0, otherwise returns 0. */
|
/** Returns 1 if @var{a} > 0, otherwise returns 0. */
|
||||||
gboolean gnc_numeric_positive_p(gnc_numeric a);
|
gboolean gnc_numeric_positive_p(gnc_numeric a);
|
||||||
|
|
||||||
/** Equivalence predicate: Returns TRUE (1) if a and b are exactly the
|
/** Equivalence predicate: Returns TRUE (1) if a and b are
|
||||||
* same (same numerator and denominator)
|
* exactly the same (have the same numerator and denominator)
|
||||||
*/
|
*/
|
||||||
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b);
|
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b);
|
||||||
|
|
||||||
/** Equivalence predicate: Returns TRUE (1) if a and b represent
|
/** Equivalence predicate: Returns TRUE (1) if a and b represent
|
||||||
* exactly the same number (ratio of numerator to denominator is
|
* the same number. That is, return TRUE if the ratios, when
|
||||||
* exactly equal)
|
* reduced by eliminating common factors, are identical.
|
||||||
*/
|
*/
|
||||||
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b);
|
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b);
|
||||||
|
|
||||||
/** Equivalence predicate: Returns TRUE (1) if after both are
|
/** Equivalence predicate:
|
||||||
* converted to DENOM using method HOW, a and b are
|
* Convert both @var{a} and @var{b} to @var{denom} using the
|
||||||
* gnc_numeric_equal().
|
* specified DENOM and method HOW, and compare numerators
|
||||||
|
* the results using gnc_numeric_equal.
|
||||||
|
*
|
||||||
|
@example
|
||||||
|
For example, if @code{@var{a} == 7/16} and @code{@var{b} == 3/4},
|
||||||
|
@code{gnc_numeric_same(@var{a}, @var{b}, 2, GNC_HOW_RND_TRUNC) == 1}
|
||||||
|
because both 7/16 and 3/4 round to 1/2 under truncation. However,
|
||||||
|
@code{gnc_numeric_same(@var{a}, @var{b}, 2, GNC_HOW_RND_ROUND) == 0}
|
||||||
|
because 7/16 rounds to 1/2 under unbiased rounding but 3/4 rounds
|
||||||
|
to 2/2.
|
||||||
|
@end example
|
||||||
*/
|
*/
|
||||||
int gnc_numeric_same(gnc_numeric a, gnc_numeric b,
|
int gnc_numeric_same(gnc_numeric a, gnc_numeric b,
|
||||||
gint64 denom, gint how);
|
gint64 denom, gint how);
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
/** @name Arithmetic operations */
|
/** @name Arithmetic operations */
|
||||||
/*@{*/
|
/** @{*/
|
||||||
|
/** Return a+b. */
|
||||||
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b,
|
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b,
|
||||||
gint64 denom, gint how);
|
gint64 denom, gint how);
|
||||||
|
|
||||||
|
/** Return a-b. */
|
||||||
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
|
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
|
||||||
gint64 denom, gint how);
|
gint64 denom, gint how);
|
||||||
|
|
||||||
@ -530,30 +413,35 @@ gnc_numeric gnc_numeric_abs(gnc_numeric a);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut for common case: gnc_numeric_add(a, b, GNC_DENOM_AUTO,
|
* Shortcut for common case: gnc_numeric_add(a, b, GNC_DENOM_AUTO,
|
||||||
* GNC_DENOM_FIXED | GNC_RND_NEVER);
|
* GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
|
||||||
*/
|
*/
|
||||||
static inline
|
static inline
|
||||||
gnc_numeric gnc_numeric_add_fixed(gnc_numeric a, gnc_numeric b) {
|
gnc_numeric gnc_numeric_add_fixed(gnc_numeric a, gnc_numeric b) {
|
||||||
return gnc_numeric_add(a, b, GNC_DENOM_AUTO,
|
return gnc_numeric_add(a, b, GNC_DENOM_AUTO,
|
||||||
GNC_DENOM_FIXED | GNC_RND_NEVER);
|
GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut for most common case: gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
|
* Shortcut for most common case: gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
|
||||||
* GNC_DENOM_FIXED | GNC_RND_NEVER);
|
* GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
|
||||||
*/
|
*/
|
||||||
static inline
|
static inline
|
||||||
gnc_numeric gnc_numeric_sub_fixed(gnc_numeric a, gnc_numeric b) {
|
gnc_numeric gnc_numeric_sub_fixed(gnc_numeric a, gnc_numeric b) {
|
||||||
return gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
|
return gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
|
||||||
GNC_DENOM_FIXED | GNC_RND_NEVER);
|
GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
|
||||||
}
|
}
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
/** @name Arithmetic functions with exact error returns */
|
/** @name Arithmetic functions with exact error returns */
|
||||||
/*@{*/
|
/** @{*/
|
||||||
|
/** The same as gnc_numeric_add, but uses @var{error} for accumulating
|
||||||
|
* conversion roundoff error. */
|
||||||
gnc_numeric gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b,
|
gnc_numeric gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b,
|
||||||
gint64 denom, gint how,
|
gint64 denom, gint how,
|
||||||
gnc_numeric * error);
|
gnc_numeric * error);
|
||||||
|
|
||||||
|
/** The same as gnc_numeric_sub, but uses @var{error} for accumulating
|
||||||
|
* conversion roundoff error. */
|
||||||
gnc_numeric gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
|
gnc_numeric gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
|
||||||
gint64 denom, gint how,
|
gint64 denom, gint how,
|
||||||
gnc_numeric * error);
|
gnc_numeric * error);
|
||||||
@ -564,18 +452,27 @@ gnc_numeric gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
|
|||||||
gnc_numeric gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b,
|
gnc_numeric gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b,
|
||||||
gint64 denom, gint how,
|
gint64 denom, gint how,
|
||||||
gnc_numeric * error);
|
gnc_numeric * error);
|
||||||
|
|
||||||
|
/** The same as @code{gnc_numeric_div}, but uses @var{error} for
|
||||||
|
* accumulating conversion roundoff error.
|
||||||
|
*/
|
||||||
gnc_numeric gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
|
gnc_numeric gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
|
||||||
gint64 denom, gint how,
|
gint64 denom, gint how,
|
||||||
gnc_numeric * error);
|
gnc_numeric * error);
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
/** @name Change denominator */
|
/** @name Change denominator */
|
||||||
/*@{*/
|
/** @{*/
|
||||||
/** change the denominator of a gnc_numeric value */
|
/** Change the denominator of a gnc_numeric value to the
|
||||||
|
* specified denominator under standard arguments
|
||||||
|
* @var{denom} and @var{how}.
|
||||||
|
*/
|
||||||
gnc_numeric gnc_numeric_convert(gnc_numeric in, gint64 denom,
|
gnc_numeric gnc_numeric_convert(gnc_numeric in, gint64 denom,
|
||||||
gint how);
|
gint how);
|
||||||
|
|
||||||
/** change the denominator of a gnc_numeric value */
|
/** Same as @code{gnc_numeric_convert}, but return a remainder
|
||||||
|
* value for accumulating conversion error.
|
||||||
|
*/
|
||||||
gnc_numeric gnc_numeric_convert_with_error(gnc_numeric in, gint64 denom,
|
gnc_numeric gnc_numeric_convert_with_error(gnc_numeric in, gint64 denom,
|
||||||
gint how,
|
gint how,
|
||||||
gnc_numeric * error);
|
gnc_numeric * error);
|
||||||
@ -585,7 +482,22 @@ gnc_numeric gnc_numeric_convert_with_error(gnc_numeric in, gint64 denom,
|
|||||||
gnc_numeric gnc_numeric_reduce(gnc_numeric in);
|
gnc_numeric gnc_numeric_reduce(gnc_numeric in);
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
|
/** Deprecated, backwards-compate definitions */
|
||||||
|
#define GNC_RND_FLOOR GNC_HOW_RND_FLOOR
|
||||||
|
#define GNC_RND_CEIL GNC_HOW_RND_CEIL
|
||||||
|
#define GNC_RND_TRUNC GNC_HOW_RND_TRUNC
|
||||||
|
#define GNC_RND_PROMOTE GNC_HOW_RND_PROMOTE
|
||||||
|
#define GNC_RND_ROUND_HALF_DOWN GNC_HOW_RND_ROUND_HALF_DOWN
|
||||||
|
#define GNC_RND_ROUND_HALF_UP GNC_HOW_RND_ROUND_HALF_UP
|
||||||
|
#define GNC_RND_ROUND GNC_HOW_RND_ROUND
|
||||||
|
#define GNC_RND_NEVER GNC_HOW_RND_NEVER
|
||||||
|
|
||||||
|
#define GNC_DENOM_EXACT GNC_HOW_DENOM_EXACT
|
||||||
|
#define GNC_DENOM_REDUCE GNC_HOW_DENOM_REDUCE
|
||||||
|
#define GNC_DENOM_LCD GNC_HOW_DENOM_LCD
|
||||||
|
#define GNC_DENOM_FIXED GNC_HOW_DENOM_FIXED
|
||||||
|
#define GNC_DENOM_SIGFIG GNC_HOW_DENOM_SIGFIG
|
||||||
|
|
||||||
|
#define GNC_DENOM_SIGFIGS(X) GNC_HOW_DENOM_SIGFIGS(X)
|
||||||
|
#define GNC_NUMERIC_GET_SIGFIGS(X) GNC_HOW_GET_SIGFIGS(X)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*@}*/
|
|
||||||
|
Loading…
Reference in New Issue
Block a user