I'm trying to develop a program that stores currency values. In my particular application I only care about two decimal of precision (cents) but have read it's a good idea (for accuracy when dealing with interest rates) to store 4 digits.
I didn't notice a "currency" class in either boost or C++14 (perhaps I overlooked, if so please point out). The main motivation for me using a class instead of just "double" is I was concerned about inaccuracies that, in my experience, seem to pop up in the last 3-4 digits stored by doubles when multiplying / dividing.
I don't have any locale-specific features included because it seems, at least as far as string formatting, boost does have a way to deal with that problem.
Please provide feedback on this class. Any alterations that should be made / best practices, etc.
currency.hpp
#pragma once
#include <type_traits>
#include <stdint.h>
class currency {
private:
static constexpr long double FACTOR = 10000;
typedef int64_t p_int;
p_int value;
public:
long double round() {
p_int num = value / 100;
int8_t digs = value % 100;
if (digs >= 50) { ++num; }
return (long double)(num) / 100;
}
// Destructor and Constructors
~currency() {}
currency() { value = 0; }
currency(const currency& obj) { value = obj.value; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
currency(const N& n) { value = n * FACTOR; }
// Assignment operator
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
currency& operator=(const N& n) { value = n * FACTOR; return *this; }
currency& operator=(const currency& n) { value = n.value; return *this; }
// Comparison operators
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
bool operator==(const N& n) { return value == (p_int)(n * FACTOR); }
bool operator==(const currency& n) { return value == n.value; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
bool operator<(const N& n) { return value < (p_int)(n * FACTOR); }
bool operator<(const currency& n) { return value < n.value; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
bool operator<=(const N& n) { return value <= (p_int)(n * FACTOR); }
bool operator<=(const currency& n) { return value <= n.value; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
bool operator>(const N& n) { return value > (p_int)(n * FACTOR); }
bool operator>(const currency& n) { return value > n.value; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
bool operator>=(const N& n) { return value >= (int)(n * FACTOR); }
bool operator>=(const currency& n) { return value >= n.value; }
// Compound Arithmetic operators
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
currency& operator+=(const N& n) { value += n * FACTOR; return *this; }
currency& operator+=(const currency& n) { value += n.value; return *this; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
currency& operator-=(const N& n) { value += n * -FACTOR; return *this; }
currency& operator-=(const currency& n) { value -= n.value; return *this; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
currency& operator/=(const N& n) { value /= n; return *this; }
currency& operator/=(const currency& n) { value /= (n.value / FACTOR); return *this; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
currency& operator*=(const N& n) { value *= n; return *this; }
currency& operator*=(const currency& n) { value *= (n.value / FACTOR); return *this; }
// Arithmetic Operators
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
currency operator+(const N& n) { currency t(*this); return t += n; }
currency operator+(const currency& n) { currency t(*this); return t += n; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
currency operator-(const N& n) { currency t(*this); return t -= n; }
currency operator-(const currency& n) { currency t(*this); return t -= n; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
currency operator/(const N& n) { currency t(*this); return t /= n; }
currency operator/(const currency& n) { currency t(*this); return t /= n; }
template <typename N,
typename std::enable_if<std::is_arithmetic<N>::value>::type* = nullptr>
currency operator*(const N& n) { currency t(*this); return t *= n; }
currency operator*(const currency& n) { currency t(*this); return t *= n; }
};
currency.cpp
#include "currency.hpp"
constexpr long double currency::FACTOR;