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