Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3e2fc70
Expand the basics section
mborland Jan 9, 2025
14aad5f
Address review comments
mborland Jan 9, 2025
6db7051
Address review comments
mborland Jan 9, 2025
113de3d
Merge pull request #785 from cppalliance/basics
mborland Jan 10, 2025
17e5adb
Remove domain error verbiage for quantexp
mborland Jan 15, 2025
7ad9836
Update jamfile
mborland Jan 15, 2025
b978857
Add Make corpus python file
mborland Jan 15, 2025
6e99976
Add note on normalization in charconv to docs
mborland Jan 15, 2025
5fdab9f
Merge pull request #789 from cppalliance/fuzzing
mborland Jan 15, 2025
c7f1ca1
Merge pull request #790 from cppalliance/787
mborland Jan 15, 2025
54c61c3
Merge pull request #788 from cppalliance/786
mborland Jan 15, 2025
158b491
Fix typo
mborland Jan 15, 2025
ee92e74
Fix missing class decimalXX {
mborland Jan 15, 2025
538ac21
Add privately reported crash reproducer
mborland Jan 17, 2025
6ad83b8
Don't pass SIZE_T_MAX to memset
mborland Jan 17, 2025
23cfbfd
Strip trailing zeros from significand fixed format with no precision
mborland Jan 17, 2025
0328e0f
Exercise the no precision specified to_chars path
mborland Jan 17, 2025
49ba4bb
Add additional powers of ten testing
mborland Jan 18, 2025
a965958
Add buffer and use constexpr memset
mborland Jan 18, 2025
8a6cf92
Revert fuzz duration
mborland Jan 18, 2025
dccbab7
Ignore GCC-12 warning
mborland Jan 18, 2025
227588c
Merge pull request #793 from cppalliance/to_chars_10s
mborland Jan 18, 2025
f6f27a2
Revert "Merge pull request #789 from cppalliance/fuzzing"
mborland Jan 18, 2025
394daf2
Merge pull request #797 from cppalliance/revert_fuzz
mborland Jan 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/decimal.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ https://www.boost.org/LICENSE_1_0.txt
Matt Borland and Chris Kormanyos

include::decimal/overview.adoc[]
include::decimal/basics.adoc[]
include::decimal/api_reference.adoc[]
include::decimal/generic_decimal.adoc[]
include::decimal/decimal32.adoc[]
Expand Down
85 changes: 85 additions & 0 deletions doc/decimal/basics.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
////
Copyright 2025 Matt Borland
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////

[#basics]
= Basic Usage
:idprefix: basics_

== Construction of Decimal Types

Every decimal type can be constructed in a few ways:

1) The parameters to the constructor are like so:

[source, c++]
----
template <typename T, typename T2>
constexpr decimal32(T coeff, T2 exp, bool sign = false) noexcept;
----

Where types `T` and `T2` are integral types (signed and unsigned are both allowed).
Lastly the sign follows the convention of `signbit` where `false` is positive and `true` is negative.
If both a negative coefficient and a sign are passed then the resulting decimal number will be negative.
The final number constructed is in the form (sign || coeff < 0 ? -1 : 1) x abs(coeff) x 10^exp.

[souce, c++]
----
boost::decimal::decimal32 a {1, 0}; // constructs 1
boost::decimal::decimal32 b {-2, 0}; // constructs -2
boost::decimal::decimal32 c {2, 0, true}; // Also constructs -2
boost::decimal::decimal32 d {-2, 0, true}; // Also constructs -2
boost::decimal::decimal32 e {5, 5}; // constructs 5x10^5
boost::decimal::decimal32 f {1234, -3} // constructs 1.234 or 1234x10^-3
----

2) A decimal number can be explicitly or implicitly constructed from an integer.
For example:

[source, c++]
----
boost::decimal::decimal64 g = 1;
boost::decimal::decimal32 h {-4};
----

3) A decimal number can only be explicitly constructed from a floating point type.
For example:

[source, c++]
----
boost::decimal::decimal128 pi {3.14};
----

NOTE: 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

== Using the Library

The entire library should be accessed using the convenience header `<boost/decimal.hpp>`.
A short example of the basic usage:

[source, c++]
----
#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 a {1, -1}; // 1e-1 or 0.1
constexpr decimal64 b {2, -1}; // 2e-1 or 0.2

// Outputs 0.30000000000000000
std::cout << a + b << std::endl;

return 0;
}

----
2 changes: 2 additions & 0 deletions doc/decimal/charconv.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ BOOST_DECIMAL_CONSTEXPR std::to_chars_result to_chars(char* first, char* last, D
} //namespace boost
----

All `to_chars` functions ignore the effects of cohorts, and instead output normalized values.

NOTE: `BOOST_DECIMAL_CONSTEXPR` is defined if:

- `_MSC_FULL_VER` >= 192528326
Expand Down
2 changes: 1 addition & 1 deletion doc/decimal/cmath.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ constexpr int quantexp128(decimal128 x) noexcept;

Effects: if x is finite, returns its quantum exponent.

Otherwise, a domain error occurs and `INT_MIN` is returned.
Otherwise, `INT_MIN` is returned.

=== quantized

Expand Down
4 changes: 4 additions & 0 deletions doc/decimal/decimal128.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ The encoding of Decimal128 is in the <<conversions, BID format>>.
namespace boost {
namespace decimal {

class decimal128 {

// Paragraph numbers are from ISO/IEC DTR 24733

// 3.2.4.1 construct/copy/destroy
Expand Down Expand Up @@ -85,6 +87,8 @@ explicit constexpr operator std::bfloat16_t() const noexcept;
explicit constexpr operator decimal32() const noexcept;
explicit constexpr operator decimal64() const noexcept;

}; // class decimal128

} //namespace decimal
} //namespace boost

Expand Down
4 changes: 4 additions & 0 deletions doc/decimal/decimal128_fast.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ As is often the case this trades space for time by having greater storage width
namespace boost {
namespace decimal {

class decimal128_fast {

// Paragraph numbers are from ISO/IEC DTR 24733

// 3.2.4.1 construct/copy/destroy
Expand Down Expand Up @@ -85,6 +87,8 @@ explicit constexpr operator std::bfloat16_t() const noexcept;
explicit constexpr operator decimal32() const noexcept;
explicit constexpr operator decimal64() const noexcept;

}; // class decimal128_fast

} //namespace decimal
} //namespace boost

Expand Down
4 changes: 4 additions & 0 deletions doc/decimal/decimal32.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ The encoding of Decimal32 is in the <<conversions, BID format>>.
namespace boost {
namespace decimal {

class decimal32 {

// Paragraph numbers are from ISO/IEC DTR 24733

// 3.2.2.1 construct/copy/destroy
Expand Down Expand Up @@ -85,6 +87,8 @@ explicit constexpr operator std::bfloat16_t() const noexcept;
explicit constexpr operator decimal64() const noexcept;
explicit constexpr operator decimal128() const noexcept;

}; // class decimal32

} //namespace decimal
} //namespace boost

Expand Down
4 changes: 4 additions & 0 deletions doc/decimal/decimal32_fast.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ As is often the case this trades space for time by having greater storage width
namespace boost {
namespace decimal {

class decimal32_fast {

// Paragraph numbers are from ISO/IEC DTR 24733

// 3.2.2.1 construct/copy/destroy
Expand Down Expand Up @@ -85,6 +87,8 @@ explicit constexpr operator std::bfloat16_t() const noexcept;
explicit constexpr operator decimal64() const noexcept;
explicit constexpr operator decimal128() const noexcept;

}; // class decimal32_fast

} //namespace decimal
} //namespace boost

Expand Down
4 changes: 4 additions & 0 deletions doc/decimal/decimal64.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ The encoding of Decimal64 is in the <<conversions, BID format>>.
namespace boost {
namespace decimal {

class decimal64 {

// Paragraph numbers are from ISO/IEC DTR 24733

// 3.2.3.1 construct/copy/destroy
Expand Down Expand Up @@ -85,6 +87,8 @@ explicit constexpr operator std::bfloat16_t() const noexcept;
explicit constexpr operator decimal32() const noexcept;
explicit constexpr operator decimal128() const noexcept;

}; // class decimal64

} //namespace decimal
} //namespace boost

Expand Down
4 changes: 4 additions & 0 deletions doc/decimal/decimal64_fast.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ As is often the case this trades space for time by having greater storage width
namespace boost {
namespace decimal {

class decimal64_fast {

// Paragraph numbers are from ISO/IEC DTR 24733

// 3.2.3.1 construct/copy/destroy
Expand Down Expand Up @@ -85,6 +87,8 @@ explicit constexpr operator std::bfloat16_t() const noexcept;
explicit constexpr operator decimal32() const noexcept;
explicit constexpr operator decimal128() const noexcept;

}; // class decimal64_fast

} //namespace decimal
} //namespace boost

Expand Down
31 changes: 0 additions & 31 deletions doc/decimal/overview.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,3 @@ as well as emulated PPC64LE and STM32 using QEMU with the following compilers:

Tested on https://github.com/cppalliance/decimal/actions[Github Actions] and https://drone.cpp.al/cppalliance/decimal[Drone].
Coverage can be found on https://app.codecov.io/gh/cppalliance/decimal[Codecov].

== Basic Usage

The entire library should be accessed using the convince header `<boost/decimal.hpp>`.
A short example of the basic usage:

[source, c++]
----
#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;

// Construct the two decimal values
constexpr decimal64 a {1, -1}; // 1e-1 or 0.1
constexpr decimal64 b {2, -1}; // 2e-1 or 0.2

// Outputs 0.30000000000000000
std::cout << a + b << std::endl;

return 0;
}

----

35 changes: 21 additions & 14 deletions include/boost/decimal/charconv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,16 +542,16 @@ BOOST_DECIMAL_CONSTEXPR auto to_chars_fixed_impl(char* first, char* last, const
{
append_trailing_zeros = true;
}
}

// In general formatting we remove trailing 0s
if (fmt == chars_format::general)
{

const auto zeros_removal {remove_trailing_zeros(significand)};
significand = zeros_removal.trimmed_number;
exponent += static_cast<int>(zeros_removal.number_of_removed_zeros);
num_dig -= static_cast<int>(zeros_removal.number_of_removed_zeros);
}
// In general formatting we remove trailing 0s
// Same with unspecified precision fixed formatting
if ((precision == -1 && fmt == chars_format::fixed) || fmt == chars_format::general)
{
const auto zeros_removal {remove_trailing_zeros(significand)};
significand = zeros_removal.trimmed_number;
exponent += static_cast<int>(zeros_removal.number_of_removed_zeros);
num_dig -= static_cast<int>(zeros_removal.number_of_removed_zeros);
}

// Make sure the result will fit in the buffer
Expand All @@ -569,25 +569,32 @@ BOOST_DECIMAL_CONSTEXPR auto to_chars_fixed_impl(char* first, char* last, const
*first++ = '0';
return {first, std::errc()};
}
else if (num_leading_zeros > precision)
else if (precision != -1 && num_leading_zeros > precision)
{
*first++ = '0';
*first++ = '.';
std::memset(first, '0', static_cast<std::size_t>(precision));
boost::decimal::detail::memset(first, '0', static_cast<std::size_t>(precision));
return {first + precision, std::errc()};
}
else
{
*first++ = '0';
*first++ = '.';
std::memset(first, '0', static_cast<std::size_t>(num_leading_zeros));
boost::decimal::detail::memset(first, '0', static_cast<std::size_t>(num_leading_zeros));
first += num_leading_zeros;

// We can skip the rest if there's nothing more to do for the required precision
if (significand == 0)
{
std::memset(first, '0', static_cast<std::size_t>(precision - num_leading_zeros));
return {first + precision, std::errc()};
if (precision - num_leading_zeros > 0)
{
boost::decimal::detail::memset(first, '0', static_cast<std::size_t>(precision - num_leading_zeros));
return {first + precision, std::errc()};
}
else
{
return {first, std::errc()};
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions include/boost/decimal/detail/memcpy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#if defined(__GNUC__) && __GNUC__ >= 10
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstringop-overflow"
# pragma GCC diagnostic ignored "-Warray-bounds"
# define BOOST_DECIMAL_STRINGOP_OVERFLOW_DISABLED
#endif

Expand Down
1 change: 1 addition & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ project : requirements
run-fail benchmarks.cpp ;
run compare_dec128_and_fast.cpp ;
compile-fail concepts_test.cpp ;
run crash_report_1.cpp ;
run github_issue_426.cpp ;
run github_issue_448.cpp ;
run-fail github_issue_519.cpp ;
Expand Down
27 changes: 27 additions & 0 deletions test/crash_report_1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/decimal.hpp>
#include <boost/core/lightweight_test.hpp>
#include <iostream>

using namespace boost::decimal;

int main()
{
char buffer[64]{};
const auto print_val {0.000001_df};

const auto r = boost::decimal::to_chars(
buffer,
buffer + sizeof(buffer),
print_val,
boost::decimal::chars_format::fixed
);
*r.ptr = '\0';

BOOST_TEST_CSTR_EQ(buffer, "0.000001");

return boost::report_errors();
}
Loading
Loading