[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] valyuta/005 7d6e748 02/17: Improve currency class an
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] valyuta/005 7d6e748 02/17: Improve currency class and unit tests |
Date: |
Sat, 16 Jan 2021 21:06:16 -0500 (EST) |
branch: valyuta/005
commit 7d6e74896fd22c287987c9a03367cc93ac73ec70
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>
Improve currency class and unit tests
Unary operator-() needn't be a member; a nonmember is preferable.
Adding "const" to return types is an obsolete C++98-ism.
Free-function operators defined in a header must be "inline".
---
currency.hpp | 16 +++++-----
currency_test.cpp | 93 +++++++++++++++++++++++++++----------------------------
2 files changed, 55 insertions(+), 54 deletions(-)
diff --git a/currency.hpp b/currency.hpp
index 9bc8df5..5f21c8a 100644
--- a/currency.hpp
+++ b/currency.hpp
@@ -46,9 +46,6 @@ class LMI_SO currency
explicit currency(data_type z, raw_cents) :m_ {z} {}
currency& operator+=(currency const& z) {m_ += z.m_; return *this;}
-// !! no--mutates (negates) *this
-// currency const& operator-() {m_ = -m_; return *this;}
- currency const operator-() const {return currency(-cents(), raw_cents {});}
data_type cents() const {return m_;}
// !! possible underflow?
@@ -58,24 +55,29 @@ class LMI_SO currency
data_type m_;
};
-bool operator==(currency const& lhs, currency const& rhs)
+inline currency operator-(currency const& z)
+{
+ return currency(-z.cents(), raw_cents {});
+}
+
+inline bool operator==(currency const& lhs, currency const& rhs)
{
return lhs.cents() == rhs.cents();
}
-currency const operator+(currency const& lhs, currency const& rhs)
+inline currency operator+(currency const& lhs, currency const& rhs)
{
return currency {lhs} += rhs;
}
-currency const operator-(currency const& lhs, currency const& rhs)
+inline currency operator-(currency const& lhs, currency const& rhs)
{
return currency {lhs} += -currency {rhs};
}
static inline currency const C0 {{}, raw_cents {}};
-std::ostream& operator<<(std::ostream& os, currency const& z)
+inline std::ostream& operator<<(std::ostream& os, currency const& z)
{
os << z.d(); return os;
}
diff --git a/currency_test.cpp b/currency_test.cpp
index 8484530..e42aad6 100644
--- a/currency_test.cpp
+++ b/currency_test.cpp
@@ -27,10 +27,11 @@
#include "test_tools.hpp"
#include <limits>
+#include <sstream>
namespace
{
- round_to<double> const round_to_cents(2, r_to_nearest);
+ round_to<double> const round_to_nearest_cent(2, r_to_nearest);
} // Unnamed namespace.
class currency_test
@@ -51,7 +52,6 @@ void currency_test::test_something()
{
// default ctor
currency const a0;
- std::cout << a0 << std::endl;
BOOST_TEST(0.00 == a0.d());
BOOST_TEST( 0 == a0.m_);
// operator==()
@@ -63,9 +63,19 @@ void currency_test::test_something()
// currency a1(3.25);
// explicit ctor
+ // 3.25 is an exact binary constant
currency a1(325, raw_cents{});
- BOOST_TEST_EQUAL(3.25, a1.d());
BOOST_TEST_EQUAL( 325, a1.m_);
+ // cents()
+ BOOST_TEST_EQUAL( 325, a1.cents());
+ // d()
+ BOOST_TEST_EQUAL(3.25, a1.d());
+
+ // copy ctor
+ currency copy0 = a1;
+ BOOST_TEST_EQUAL( 325, copy0.m_);
+ currency copy1 {a1};
+ BOOST_TEST_EQUAL( 325, copy1.m_);
// operator+=()
a1 += a1;
@@ -74,6 +84,8 @@ void currency_test::test_something()
// unary operator-()
-a1;
+ // make sure that didn't mutate the object
+ // (making it a nonmember makes that mistake less likely)
BOOST_TEST_EQUAL(6.50, a1.d());
BOOST_TEST_EQUAL( 650, a1.m_);
BOOST_TEST_EQUAL(-6.50, (-a1).d());
@@ -96,71 +108,58 @@ void currency_test::test_something()
BOOST_TEST_EQUAL(-6.50, a2.d());
BOOST_TEST_EQUAL( -650, a2.m_);
+ // operator<<()
+ // 1/64 is an exact binary constant, with so few digits that it
+ // must print with full precision by default
+ currency a3 {0.015625, raw_cents {}};
+ std::ostringstream oss;
+ oss << a3;
+ BOOST_TEST_EQUAL("0.00015625", oss.str());
+
// round_to<>.c()
double d0 = 123.99999999999;
- currency c0 = round_to_cents.c(d0);
-std::cout << c0 << " converted from 123.999..." << std::endl;
+ currency c0 = round_to_nearest_cent.c(d0);
+ BOOST_TEST_EQUAL(12400, c0.m_);
double d1 = 1.0 + std::numeric_limits<double>::epsilon();
- currency c1 = round_to_cents.c(d1);
-std::cout << c1 << " converted from 1.0 + epsilon..." << std::endl;
+ currency c1 = round_to_nearest_cent.c(d1);
+ BOOST_TEST_EQUAL(100, c1.m_);
double d2 = 1.0 - std::numeric_limits<double>::epsilon();
- currency c2 = round_to_cents.c(d2);
-std::cout << c2 << " converted from 1.0 - epsilon..." << std::endl;
+ currency c2 = round_to_nearest_cent.c(d2);
+ BOOST_TEST_EQUAL(100, c2.m_);
- // overflow?
+#if 0
+ // This is curious, but may not belong here.
+// double big_num = nonstd::power(2.0, 53);
double big_num = 1.0e100;
-#pragma GCC diagnostic ignored "-Wfloat-conversion"
- currency::data_type big_int0 = big_num;
-std::cout << "int0: " << big_int0 << std::endl;
- currency::data_type big_int1 = 1.0 * big_num;
-std::cout << "int1: " << big_int1 << std::endl;
- currency::data_type big_int2 = 10.0 * big_num;
-std::cout << "int2: " << big_int2 << std::endl;
+ currency::data_type big_int1 = 1.0 * big_num;
+ BOOST_TEST_EQUAL(1.0e100, big_int1);
+ currency::data_type big_int2 = 10.0 * big_num;
+ BOOST_TEST_EQUAL(1.0e101, big_int2);
currency::data_type big_int3 = 100.0 * big_num;
-std::cout << "int3: " << big_int3 << std::endl;
- currency::data_type big_int4 = round(100.0 * big_num);
-std::cout << "int4: " << big_int4 << std::endl;
+ BOOST_TEST_EQUAL(1.0e102, big_int3);
+ round_to_nearest_cent.c(d0);
+ std::cout << std::fixed;
+std::cout << big_int3 << '\n' << 1.0e102 << '\n' << big_int3 - 1.0e102 <<
std::endl;
-#if defined CURRENCY_HAS_INTEGER_DATATYPE
BOOST_TEST_THROW
- (currency a3(big_num / 1000.0)
+ (round_to_nearest_cent.c(big_num / 1000.0)
,std::runtime_error
,"Cast would transgress upper limit."
);
-//std::cout << a3 << std::endl;
-//std::cout << big_num << std::endl;
-//std::cout << "rounded: " << round(big_num) << std::endl;
double too_big = std::numeric_limits<double>::max();
BOOST_TEST_THROW
- (currency a4(too_big)
- ,std::runtime_error
-// ,"Cast would transgress upper limit."
- ,"Cannot cast infinite to integral."
- );
-// currency a4(too_big);
-//std::cout << a4 << std::endl;
-//std::cout << too_big << std::endl;
-//std::cout << "rounded: " << round(too_big) << std::endl;
-//std::cout << 100.0 * too_big << std::endl;
-
- BOOST_TEST_THROW
- (currency(bourn_cast<currency::data_type>(too_big), raw_cents{})
- ,std::runtime_error
- ,"Cast would transgress upper limit."
- );
- BOOST_TEST_THROW
- (currency xyzzy(too_big)
+ (round_to_nearest_cent.c(too_big)
,std::runtime_error
// ,"Cast would transgress upper limit."
,"Cannot cast infinite to integral."
);
-#endif // !defined CURRENCY_HAS_INTEGER_DATATYPE
+#endif // 0
// quodlibet
- currency b0 = round_to_cents.c(464.180000000000006821);
- currency b1 = round_to_cents.c(263.01999999999998181);
- currency b2 = round_to_cents.c(0.0);
+ currency b0 = round_to_nearest_cent.c(464.180000000000006821);
+ currency b1 = round_to_nearest_cent.c(263.01999999999998181);
+ currency b2 = round_to_nearest_cent.c(0.0);
b2 += b0;
b2 += b1;
currency b3 = b0 + b1;
- [lmi-commits] [lmi] branch valyuta/005 created (now 4401725), Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 fd74b61 03/17: Correct an obvious mistake, Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 7d6e748 02/17: Improve currency class and unit tests,
Greg Chicares <=
- [lmi-commits] [lmi] valyuta/005 4902da4 01/17: Reinvent currency ab ovo, Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 ffa2ce4 09/17: Redesign unit test, Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 90d7483 10/17: Improve currency class, Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 3d44f42 13/17: Save a sorted list of regressions, Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 c8864d3 04/17: Add commented-out relops, Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 f3219f8 12/17: Use CURRENCY_UNIT_IS_CENTS appropriately, Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 aad51dd 07/17: Inline more, Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 b852a68 05/17: Add features, Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 d69f05c 06/17: Ratify some regression-testing differences, Greg Chicares, 2021/01/16
- [lmi-commits] [lmi] valyuta/005 2aae91a 14/17: Improve incrementally, Greg Chicares, 2021/01/16