gnucash stable: [gnc-euro.cpp] store euro rates as GncNumeric

Christopher Lam clam at code.gnucash.org
Fri Jul 10 09:04:26 EDT 2026


Updated	 via  https://github.com/Gnucash/gnucash/commit/b3e80748 (commit)
	from  https://github.com/Gnucash/gnucash/commit/9db7b443 (commit)



commit b3e8074890230e4413ab963c28cfff7afd722265
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Fri Jul 10 07:06:53 2026 +0400

    [gnc-euro.cpp] store euro rates as GncNumeric
    
    this increases euro conversion rounding accuracy

diff --git a/libgnucash/engine/gnc-euro.cpp b/libgnucash/engine/gnc-euro.cpp
index e7a71e0323..a46fe41c97 100644
--- a/libgnucash/engine/gnc-euro.cpp
+++ b/libgnucash/engine/gnc-euro.cpp
@@ -20,39 +20,40 @@
 \********************************************************************/
 
 #include <string>
-#include <map>
+#include <boost/container/flat_map.hpp>
 #include <optional>
 
 #include "gnc-euro.h"
 #include "gnc-session.h"
+#include <gnc-numeric.hpp>
 
-/* The rates are per EURO and are converted to GncNumeric  */
-static const std::map<std::string,double> gnc_euro_rates =
+/* The rates are per EURO and are denoted in GncNumeric  */
+static const boost::container::flat_map <std::string, GncNumeric> gnc_euro_rates =
 {
-    { "ATS",  13.7603 },  /* austrian schilling */
-    { "BEF",  40.3399 },  /* belgian franc */
-    { "BGN",  1.95583 },  /* Bulgarian lev */
-    { "CYP",  .585274 },  /* cyprus pound */
-    { "DEM",  1.95583 },  /* german mark */
-    { "EEK",  15.6466 },  /* Estonian Kroon */
-    { "ESP",  166.386 },  /* spanish peseta */
-    { "EUR",  1.00000 },  /* euro */
-    { "FIM",  5.94573 },  /* finnmark */
-    { "FRF",  6.55957 },  /* french franc */
-    { "GRD",  340.750 },  /* greek drachma */
-    { "HRK",  7.53450 },  /* Croatian kuna */
-    { "IEP",  .787564 },  /* irish pound */
-    { "ITL",  1936.27 },  /* italian lira */
-    { "LUF",  40.3399 },  /* luxembourg franc */
-    { "LVL",  .702804 },  /* latvian lats */
-    { "MTL",  .429300 },  /* maltese lira */
-    { "NLG",  2.20371 },  /* netherland gulden */
-    { "PTE",  200.482 },  /* portuguese escudo */
-    { "SIT",  239.640 },  /* slovenian tolar */
-    { "SKK",  30.1260 }   /* slovak koruna */
+    { "ATS", {137603,   10000} }, /* austrian schilling */
+    { "BEF", {403399,   10000} }, /* belgian franc */
+    { "BGN", {195583,  100000} }, /* Bulgarian lev */
+    { "CYP", {585274, 1000000} }, /* cyprus pound */
+    { "DEM", {195583,  100000} }, /* german mark */
+    { "EEK", {156466,   10000} }, /* Estonian Kroon */
+    { "ESP", {166386,    1000} }, /* spanish peseta */
+    { "EUR", {     1,       1} }, /* euro */
+    { "FIM", {594573,  100000} }, /* finnmark */
+    { "FRF", {655957,  100000} }, /* french franc */
+    { "GRD", {340750,    1000} }, /* greek drachma */
+    { "HRK", {753450,  100000} }, /* Croatian kuna */
+    { "IEP", {787564, 1000000} }, /* irish pound */
+    { "ITL", {193627,     100} }, /* italian lira */
+    { "LUF", {403399,   10000} }, /* luxembourg franc */
+    { "LVL", {702804, 1000000} }, /* latvian lats */
+    { "MTL", {429300, 1000000} }, /* maltese lira */
+    { "NLG", {220371,  100000} }, /* netherland gulden */
+    { "PTE", {200482,    1000} }, /* portuguese escudo */
+    { "SIT", {239640,    1000} }, /* slovenian tolar */
+    { "SKK", {301260,   10000} }  /* slovak koruna */
 };
 
-static std::optional<double>
+static std::optional<GncNumeric>
 get_euro_rate (const gnc_commodity * currency)
 {
     if (!currency || !gnc_commodity_is_iso(currency))
@@ -82,13 +83,11 @@ gnc_convert_to_euro(const gnc_commodity * currency, gnc_numeric value)
     if (!euro_rate)
         return gnc_numeric_zero();
 
-    auto rate = double_to_gnc_numeric (*euro_rate, 100000, GNC_HOW_RND_ROUND_HALF_UP);
-
     /* round to 2 decimal places */
     /* EC Regulation 1103/97 states we should use "Round half away from zero"
      * See https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A31997R1103&qid=1662917247821
      */
-    return gnc_numeric_div (value, rate, 100, GNC_HOW_RND_ROUND_HALF_UP);
+    return gnc_numeric_convert (value / *euro_rate, 100, GNC_HOW_RND_ROUND_HALF_UP);
 }
 
 /* ------------------------------------------------------ */
@@ -100,12 +99,10 @@ gnc_convert_from_euro(const gnc_commodity * currency, gnc_numeric value)
     if (!euro_rate)
         return gnc_numeric_zero();
 
-    auto rate = double_to_gnc_numeric (*euro_rate, 100000, GNC_HOW_RND_ROUND_HALF_UP);
-
     /* EC Regulation 1103/97 states we should use "Round half away from zero"
      * See http://europa.eu/legislation_summaries/economic_and_monetary_affairs/institutional_and_economic_framework/l25025_en.htm */
-    return gnc_numeric_mul (value, rate, gnc_commodity_get_fraction (currency),
-                            GNC_HOW_RND_ROUND_HALF_UP);
+    return gnc_numeric_convert (value * *euro_rate, gnc_commodity_get_fraction (currency),
+                                GNC_HOW_RND_ROUND_HALF_UP);
 }
 
 /* ------------------------------------------------------ */
@@ -117,7 +114,7 @@ gnc_euro_currency_get_rate (const gnc_commodity *currency)
     if (!euro_rate)
         return gnc_numeric_zero();
 
-    return double_to_gnc_numeric (*euro_rate, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
+    return static_cast<gnc_numeric>(*euro_rate);
 }
 
 /* ------------------------------------------------------ */
diff --git a/libgnucash/engine/test/gtest-gnc-euro.cpp b/libgnucash/engine/test/gtest-gnc-euro.cpp
index 3e1d867cf3..b8ee984bc9 100644
--- a/libgnucash/engine/test/gtest-gnc-euro.cpp
+++ b/libgnucash/engine/test/gtest-gnc-euro.cpp
@@ -67,7 +67,7 @@ TEST_F(Currencies, is_euro_currency)
 TEST_F(Currencies, convert_to_euro)
 {
     gnc_numeric value{314159, 100};
-    gnc_numeric cyp_eur_amount{536776, 100}; // calc gets 5367.76
+    gnc_numeric cyp_eur_amount{536773, 100};
     auto cyp{gnc_commodity_table_lookup(m_table, currency, "CYP")};
     ASSERT_NE(cyp, nullptr);
     auto amount{gnc_convert_to_euro(cyp, value)};
@@ -111,8 +111,8 @@ TEST_F(Currencies, convert_to_euro)
 
 TEST_F(Currencies, convert_from_euro)
 {
-    gnc_numeric value{314159, 100}; //.787564 * 3141.59 = 2472.20
-    gnc_numeric eur_iep_amount{247419, 100};
+    gnc_numeric value{314159, 100};
+    gnc_numeric eur_iep_amount{247420, 100};
     auto iep{gnc_commodity_table_lookup(m_table, currency, "IEP")};
     ASSERT_NE(iep, nullptr);
     auto amount{gnc_convert_from_euro(iep, value)};



Summary of changes:
 libgnucash/engine/gnc-euro.cpp            | 63 +++++++++++++++----------------
 libgnucash/engine/test/gtest-gnc-euro.cpp |  6 +--
 2 files changed, 33 insertions(+), 36 deletions(-)



More information about the gnucash-changes mailing list