gnucash maint: Multiple changes pushed
John Ralls
jralls at code.gnucash.org
Tue Nov 27 08:17:33 EST 2018
Updated via https://github.com/Gnucash/gnucash/commit/61cd7999 (commit)
via https://github.com/Gnucash/gnucash/commit/536606a8 (commit)
from https://github.com/Gnucash/gnucash/commit/e57d4278 (commit)
commit 61cd7999f34a3976fd45bf4668d7012ab3ca4835
Author: John Ralls <jralls at ceridwen.us>
Date: Tue Nov 27 22:11:36 2018 +0900
Fix half-up, half-down, and banker's rounding for negative numbers.
We need to compare the magnitudes of the remainder and the denominator
in order to round negative numbers correctly. Note that while gnc_numeric
is constrained to a positive denominator the C++ rounding functions cannot
assume that constraint in all cases.
Combined with the previous commit, this fixes
Bug 796949 - Incorrect conversion of 0,01 USD to EUR
diff --git a/libgnucash/engine/gnc-rational-rounding.hpp b/libgnucash/engine/gnc-rational-rounding.hpp
index f5cdb50..6923017 100644
--- a/libgnucash/engine/gnc-rational-rounding.hpp
+++ b/libgnucash/engine/gnc-rational-rounding.hpp
@@ -23,6 +23,7 @@
#ifndef __GNC_RATIONAL_ROUNDING_HPP__
#define __GNC_RATIONAL_ROUNDING_HPP__
#include "gnc-numeric.h"
+#include "gnc-int128.hpp"
enum class RoundType
{
@@ -105,7 +106,18 @@ round(T num, T den, T rem, RT2T<RoundType::half_down>)
{
if (rem == 0)
return num;
- if (rem * 2 > den)
+ if (std::abs(rem * 2) > std::abs(den))
+ return num + (num < 0 ? -1 : 1);
+ return num;
+}
+
+template <> inline GncInt128
+round<GncInt128>(GncInt128 num, GncInt128 den, GncInt128 rem,
+ RT2T<RoundType::half_down>)
+{
+ if (rem == 0)
+ return num;
+ if (rem.abs() * 2 > den.abs())
return num + (num < 0 ? -1 : 1);
return num;
}
@@ -115,7 +127,18 @@ round(T num, T den, T rem, RT2T<RoundType::half_up>)
{
if (rem == 0)
return num;
- if (rem * 2 >= den)
+ if (std::abs(rem) * 2 >= std::abs(den))
+ return num + (num < 0 ? -1 : 1);
+ return num;
+}
+
+template <> inline GncInt128
+round<GncInt128>(GncInt128 num, GncInt128 den, GncInt128 rem,
+ RT2T<RoundType::half_up>)
+{
+ if (rem == 0)
+ return num;
+ if (rem.abs() * 2 >= den.abs())
return num + (num < 0 ? -1 : 1);
return num;
}
@@ -125,9 +148,21 @@ round(T num, T den, T rem, RT2T<RoundType::bankers>)
{
if (rem == 0)
return num;
- if (rem * 2 > den || (rem * 2 == den && num % 2))
+ if (std::abs(rem * 2) > std::abs(den) ||
+ (std::abs(rem * 2) == std::abs(den) && num % 2))
return num += (num < 0 ? -1 : 1);
return num;
}
+template<> inline GncInt128
+round<GncInt128>(GncInt128 num, GncInt128 den, GncInt128 rem,
+ RT2T<RoundType::bankers>)
+{
+ if (rem == 0)
+ return num;
+ if (rem.abs() * 2 > den.abs() ||
+ (rem.abs() * 2 == den.abs() && num % 2))
+ return num += (num < 0 ? -1 : 1);
+ return num;
+}
#endif //__GNC_RATIONAL_ROUNDING_HPP__
commit 536606a89c5b53ad8ef91a63a021b8e564deb3aa
Author: John Ralls <jralls at ceridwen.us>
Date: Tue Nov 27 21:25:29 2018 +0900
Fix extract_common_prices logic.
So that the returned price tuple has the two commodities of interest
converted to a common currency. Before the first pair that that shared
any random currency would be returned, perhaps creating an absurd result.
diff --git a/libgnucash/engine/gnc-pricedb.c b/libgnucash/engine/gnc-pricedb.c
index e9f1594..8f462c3 100644
--- a/libgnucash/engine/gnc-pricedb.c
+++ b/libgnucash/engine/gnc-pricedb.c
@@ -2480,7 +2480,8 @@ typedef struct
} PriceTuple;
static PriceTuple
-extract_common_prices (PriceList *from_prices, PriceList *to_prices)
+extract_common_prices (PriceList *from_prices, PriceList *to_prices,
+ const gnc_commodity *from, const gnc_commodity *to)
{
PriceTuple retval = {NULL, NULL};
GList *from_node = NULL, *to_node = NULL;
@@ -2500,8 +2501,10 @@ extract_common_prices (PriceList *from_prices, PriceList *to_prices)
to_cur = gnc_price_get_currency (to_price);
from_com = gnc_price_get_commodity (from_price);
from_cur = gnc_price_get_currency (from_price);
- if (to_com == from_com || to_com == from_cur ||
- to_cur == from_com || to_cur == from_cur)
+ if (((to_com == from_com || to_com == from_cur) &&
+ (to_com != from && to_com != to)) ||
+ ((to_cur == from_com || to_cur == from_cur) &&
+ (to_cur != from && to_cur != to)))
break;
to_price = NULL;
from_price = NULL;
@@ -2578,7 +2581,7 @@ indirect_balance_conversion (GNCPriceDB *db, gnc_numeric bal,
}
if (from_prices == NULL || to_prices == NULL)
return zero;
- tuple = extract_common_prices(from_prices, to_prices);
+ tuple = extract_common_prices(from_prices, to_prices, from, to);
gnc_price_list_destroy(from_prices);
gnc_price_list_destroy(to_prices);
if (tuple.from)
Summary of changes:
libgnucash/engine/gnc-pricedb.c | 11 +++++---
libgnucash/engine/gnc-rational-rounding.hpp | 41 ++++++++++++++++++++++++++---
2 files changed, 45 insertions(+), 7 deletions(-)
More information about the gnucash-changes
mailing list