Basic Usage
Construction of Decimal Types
Every decimal type can be constructed in a few ways:
Construction from Coefficient and Exponent
namespace boost {
namespace decimal {
enum class construction_sign
{
negative,
positive
};
template <typename UnsignedInteger, typename Integer>
constexpr decimal32_t(UnsignedInteger coefficient, Integer exponent, construction_sign resultant_sign = construction_sign::positive) noexcept;
template <typename SignedInteger, typename Integer>
constexpr decimal32_t(SignedInteger coefficient, Integer exponent) noexcept;
} // namespace decimal
} // namespace boost
As you can see you are either allowed to pass a signed integer, or specify the signedness of the resulting number, but not both.
This is designed to reduce confusion (e.g. what would be the resulting sign of {-3, 0, construction_sign::negative}?)
boost::decimal::decimal32_t a {1, 1}; // constructs 1e1 = 10
boost::decimal::decimal32_t b {-2, -1}; // constructs -2e-2 or -0.2
boost::decimal::decimal32_t c {2U, -1, construction_sign::negative}; // also constructs -2e-1 or -0.2 (Note: The coefficient must be an unsigned type)
boost::decimal::decimal32_t e {5, 5}; // constructs 5x10^5
boost::decimal::decimal32_t f {1234, -3} // constructs 1.234 or 1234x10^-3
Overflow and underflow are handled the same way that they are with binary floating point numbers i.e. they will construct an infinity or a zero.
boost::decimal::decimal64_t overflow_value {100, 10000}; // Constructs +infinity
boost::decimal::decimal64_t underflow_value {100, -10000}; // Constructs 0
Construction from Integer
A decimal number can be explicitly or implicitly constructed from an integer. For example:
boost::decimal::decimal64_t g = 1;
boost::decimal::decimal32_t h {-4};
Construction from Binary Floating Point
A decimal number can only be explicitly constructed from a floating point type. For example:
boost::decimal::decimal128_t pi {3.14};
Construction from non-finite values (e.g. std::numeric_limits<double>::quiet_NaN()) will yield the same non-finite value in the resulting decimal value.
Overflow or underflow will construct infinity or 0.
| Due to the differences in decimal and binary floating point numbers there may be a difference in the resulting representation in decimal format, and thus it is not recommended to construct from binary floating point numbers |
Fundamental Operations
The fundamental operations of numerical types (e.g. >, ==, +, etc.) are overloaded.
#include <boost/decimal.hpp>
#include <cassert>
int main()
{
constexpr boost::decimal::decimal32_t lhs {5};
constexpr boost::decimal::decimal32_t rhs {1, -1};
assert(lhs > rhs);
assert(lhs != rhs);
assert(lhs + rhs > lhs);
auto new_lhs {lhs}; // Using auto is safe when constructring from existing decimal values
new_lhs += lhs;
assert(lhs < new_lhs);
return 0;
}
Rounding
The default rounding mode for all operations is so-called "banker’s rounding", which is to nearest (with ties to even).
Similar to the standard library, the active rounding mode can be changed through floating point environment variables.
For more information see: <cfenv> Support
Using the Library
The entire library can be accessed using the convenience header <boost/decimal.hpp>.
A short example of the basic usage:
#include <boost/decimal.hpp>
#include <iostream>
#include <iomanip>
int main()
{
using namespace boost::decimal;
// Outputs 0.30000000000000004
std::cout << std::setprecision(17) << 0.1 + 0.2 << std::endl;
// Construct the two decimal values
constexpr decimal64_t a {1, -1}; // 1e-1 or 0.1
constexpr decimal64_t b {2, -1}; // 2e-1 or 0.2
// Outputs 0.30000000000000000
std::cout << a + b << std::endl;
return 0;
}