From 399a1eb9893c5b2ac8f7d268092ced3e4f109b52 Mon Sep 17 00:00:00 2001 From: Charles Day Date: Sun, 27 Jul 2008 15:33:23 +0000 Subject: [PATCH] Add a new function to the gnc_numeric library that converts denominators to exact powers of ten. BP git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@17421 57a11ea4-9604-0410-9ed3-97b8803252fd --- lib/libqof/qof/gnc-numeric.c | 76 ++++++++++++++++++++++++++++++++++++ lib/libqof/qof/gnc-numeric.h | 15 +++++++ 2 files changed, 91 insertions(+) diff --git a/lib/libqof/qof/gnc-numeric.c b/lib/libqof/qof/gnc-numeric.c index 2040702aa5..ef9b8c5bca 100644 --- a/lib/libqof/qof/gnc-numeric.c +++ b/lib/libqof/qof/gnc-numeric.c @@ -1019,6 +1019,82 @@ gnc_numeric_reduce(gnc_numeric in) return out; } + +/* ******************************************************************* + * 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) +{ + guint8 decimal_places = 0; + gnc_numeric converted_val; + gint64 fraction; + + g_return_val_if_fail(a, FALSE); + + if (gnc_numeric_check(*a) != GNC_ERROR_OK) + return FALSE; + + converted_val = *a; + fraction = converted_val.denom; + if (fraction <= 0) + return FALSE; + + 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; + } + + decimal_places += 1; + } + + if (max_decimal_places) + *max_decimal_places = decimal_places; + + *a = converted_val; + + return TRUE; +} + + /* ******************************************************************* * double_to_gnc_numeric ********************************************************************/ diff --git a/lib/libqof/qof/gnc-numeric.h b/lib/libqof/qof/gnc-numeric.h index f6d7524006..130b1091af 100644 --- a/lib/libqof/qof/gnc-numeric.h +++ b/lib/libqof/qof/gnc-numeric.h @@ -445,6 +445,21 @@ gnc_numeric gnc_numeric_convert_with_error(gnc_numeric in, gint64 denom, /** Return input after reducing it by Greated Common Factor (GCF) * elimination */ gnc_numeric gnc_numeric_reduce(gnc_numeric in); + +/** Attempt to convert the denominator to an exact power of ten without + * rounding. + * + * @param a the ::gnc_numeric value to convert + * + * @param max_decimal_places the number of decimal places of the + * converted value. This parameter may be @c NULL. + * + * @return @c TRUE if @a a has been converted or was already decimal. + * Otherwise, @c FALSE is returned and @a a and @a max_decimal_places + * remain unchanged. + ********************************************************************/ +gboolean gnc_numeric_to_decimal(gnc_numeric * a, + guint8 * max_decimal_places); /** @} */ /** @name GValue