1#ifndef SOURCEMETA_CORE_NUMERIC_UTIL_H_
2#define SOURCEMETA_CORE_NUMERIC_UTIL_H_
4#include <sourcemeta/core/numeric_decimal.h>
15namespace sourcemeta::core {
20 if constexpr (std::same_as<T, Decimal>) {
34template <
typename... Ts>
51inline constexpr auto is_digit(
const char character) ->
bool {
52 return character >=
'0' && character <=
'9';
70 return character >=
'1' && character <=
'9';
75template <
typename T>
constexpr auto is_byte(
const T &value) ->
bool {
76 if constexpr (std::same_as<T, Decimal>) {
77 return value.is_finite() && value.is_integral() && value >=
Decimal{0} &&
80 return value >= 0 && value <= std::numeric_limits<std::uint8_t>::max();
87template <
typename Div
idend,
typename Divisor>
88 requires decimal_or_integral<Dividend> && decimal_or_integral<Divisor>
89auto divide_floor(
const Dividend ÷nd,
const Divisor &divisor) {
95 assert(decimal_divisor >
Decimal{0});
96 if (decimal_divisor ==
Decimal{1}) {
97 return decimal_dividend;
98 }
else if (decimal_dividend >=
Decimal{0}) {
101 const Decimal absolute_dividend{
102 decimal_dividend.
is_signed() ? -decimal_dividend : decimal_dividend};
104 if (absolute_dividend % decimal_divisor ==
Decimal{0}) {
107 return -(quotient +
Decimal{1});
111 const auto signed_dividend{
static_cast<std::int64_t
>(dividend)};
112 const auto unsigned_divisor{
static_cast<std::uint64_t
>(divisor)};
113 assert(unsigned_divisor > 0);
114 if (unsigned_divisor == 1) {
115 return signed_dividend;
116 }
else if (signed_dividend >= 0) {
117 return static_cast<std::int64_t
>(
118 static_cast<std::uint64_t
>(signed_dividend) / unsigned_divisor);
121 const std::uint64_t absolute_dividend{
122 static_cast<std::uint64_t
>(0) -
123 static_cast<std::uint64_t
>(signed_dividend)};
124 return -(
static_cast<std::int64_t
>(
125 1 + ((absolute_dividend - 1) / unsigned_divisor)));
133template <
typename Div
idend,
typename Divisor>
134 requires decimal_or_integral<Dividend> && decimal_or_integral<Divisor>
135auto divide_ceil(
const Dividend ÷nd,
const Divisor &divisor) {
141 assert(decimal_divisor >
Decimal{0});
142 if (decimal_divisor ==
Decimal{1}) {
143 return decimal_dividend;
144 }
else if (decimal_dividend >=
Decimal{0}) {
146 if (decimal_dividend % decimal_divisor ==
Decimal{0}) {
152 const Decimal absolute_dividend{
153 decimal_dividend.
is_signed() ? -decimal_dividend : decimal_dividend};
157 const auto signed_dividend{
static_cast<std::int64_t
>(dividend)};
158 const auto unsigned_divisor{
static_cast<std::uint64_t
>(divisor)};
159 assert(unsigned_divisor > 0);
160 if (unsigned_divisor == 1) {
161 return signed_dividend;
162 }
else if (signed_dividend >= 0) {
163 if (
static_cast<std::uint64_t
>(signed_dividend) + unsigned_divisor <
165 return static_cast<std::int64_t
>(
166 (
static_cast<std::uint64_t
>(signed_dividend) / unsigned_divisor) +
167 1 - (1 / unsigned_divisor));
169 return static_cast<std::int64_t
>(
170 (
static_cast<std::uint64_t
>(signed_dividend) + unsigned_divisor -
176 return -(
static_cast<std::int64_t
>(
177 (
static_cast<std::uint64_t
>(0) -
178 static_cast<std::uint64_t
>(signed_dividend)) /
188template <
typename Minimum,
typename Maximum,
typename Multiplier>
189 requires decimal_or_integral<Minimum> && decimal_or_integral<Maximum> &&
190 decimal_or_integral<Multiplier>
192 const Multiplier &multiplier) {
200 assert(decimal_minimum <= decimal_maximum);
201 assert(decimal_multiplier >
Decimal{0});
202 return divide_floor(decimal_maximum, decimal_multiplier) -
205 const auto signed_minimum{
static_cast<std::int64_t
>(minimum)};
206 const auto signed_maximum{
static_cast<std::int64_t
>(maximum)};
207 const auto signed_multiplier{
static_cast<std::int64_t
>(multiplier)};
208 assert(signed_minimum <= signed_maximum);
209 assert(signed_multiplier > 0);
210 const auto unsigned_multiplier{
211 static_cast<std::uint64_t
>(signed_multiplier)};
212 const auto multiples_to_maximum{
214 const auto multiples_below_minimum{
221 const std::uint64_t minimum_is_multiple{
222 signed_minimum % signed_multiplier == 0 ? 1U : 0U};
223 return static_cast<std::uint64_t
>(multiples_to_maximum) -
224 static_cast<std::uint64_t
>(multiples_below_minimum) +
231template <
unsigned int T>
233 static_assert(T > 0 && T < 64,
"uint_max<T> requires 0 < T < 64");
234 return (std::uint64_t{1} << T) - 1;
241constexpr auto is_within(
const T &value,
const std::int64_t lower,
242 const std::int64_t higher)
noexcept ->
bool {
245 return std::cmp_greater_equal(value, lower) &&
246 std::cmp_less_equal(value, higher);
253constexpr auto is_within(
const T &value,
const std::uint64_t lower,
254 const std::uint64_t higher)
noexcept ->
bool {
256 return static_cast<std::uint64_t
>(value) >= lower &&
257 static_cast<std::uint64_t
>(value) <= higher;
267 const Decimal &higher) ->
bool {
268 return value >= lower && value <= higher;
273template <
typename T>
auto abs(
const T &value) {
274 if constexpr (std::same_as<T, Decimal>) {
275 return value.is_signed() ? -value : value;
279 return static_cast<std::uint64_t
>(0) -
static_cast<std::uint64_t
>(value);
281 return static_cast<std::uint64_t
>(value);
291 const std::uint8_t base,
292 const std::uint8_t exponent_start,
293 const std::uint8_t exponent_end)
295 assert(exponent_start <= exponent_end);
296 std::uint64_t result{base};
297 for (std::uint8_t exponent{1}; exponent < exponent_end; exponent++) {
300 const bool next_power_exceeds_value{result > value / base};
301 if (next_power_exceeds_value) {
302 if (exponent >= exponent_start) {
312 assert(result <= value);
319template <std::
floating_po
int Real>
321 assert(std::isfinite(value));
322 const Real threshold{
static_cast<Real
>(0.000000001)};
323 const Real base{std::floor(value)};
324 const Real next{base + 1};
325 if (next - value <= threshold) {
327 }
else if (value - base <= threshold) {
338template <std::
integral Integer, std::
floating_po
int Real>
339constexpr auto real_digits(Real value, std::uint64_t &point_position)
341 assert(std::isfinite(value));
343 std::uint64_t shifts{0};
345 Real fractional_part{std::modf(value, &integral_part)};
346 while (fractional_part != 0.0) {
352 point_position = shifts;
353 return static_cast<Integer
>(std::floor(integral_part));
370template <std::
floating_po
int Real>
371 requires(
sizeof(Real) ==
sizeof(std::uint32_t) ||
372 sizeof(Real) ==
sizeof(std::uint64_t))
374 using Bits = std::conditional_t<
sizeof(Real) ==
sizeof(std::uint32_t),
375 std::uint32_t, std::uint64_t>;
381 if (!std::isfinite(left) || !std::isfinite(right)) {
382 return left == right;
388 constexpr Bits sign_bit{Bits{1} << (8 *
sizeof(Bits) - 1)};
389 const Bits left_bits{std::bit_cast<Bits>(left)};
390 const Bits right_bits{std::bit_cast<Bits>(right)};
391 const Bits left_biased{(sign_bit & left_bits) != 0
392 ?
static_cast<Bits
>(~left_bits + Bits{1})
393 :
static_cast<Bits
>(sign_bit | left_bits)};
394 const Bits right_biased{(sign_bit & right_bits) != 0
395 ?
static_cast<Bits
>(~right_bits + Bits{1})
396 :
static_cast<Bits
>(sign_bit | right_bits)};
397 constexpr Bits maximum_units_in_last_place{4};
398 return (left_biased >= right_biased
399 ? left_biased - right_biased
400 : right_biased - left_biased) <= maximum_units_in_last_place;
auto divide_integer(const Decimal &other) const -> Decimal
Integer division (truncate toward zero).
SOURCEMETA_FORCEINLINE auto is_signed() const -> bool
Check if the decimal number is signed (negative, including -0).
Definition numeric_decimal.h:197
auto is_integral() const -> bool
auto to_decimal(const T &value) -> Decimal
Definition numeric_util.h:19
auto divide_floor(const Dividend ÷nd, const Divisor &divisor)
Definition numeric_util.h:89
auto divide_ceil(const Dividend ÷nd, const Divisor &divisor)
Definition numeric_util.h:135
auto real_equal(const Real left, const Real right) -> bool
Definition numeric_util.h:373
constexpr auto correct_ieee754(const Real value) -> Real
Definition numeric_util.h:320
constexpr auto is_byte(const T &value) -> bool
Definition numeric_util.h:75
constexpr auto is_digit(const char character) -> bool
Definition numeric_util.h:51
constexpr auto closest_smallest_exponent(const std::uint64_t value, const std::uint8_t base, const std::uint8_t exponent_start, const std::uint8_t exponent_end) -> std::uint8_t
Definition numeric_util.h:290
constexpr auto is_positive_digit(const char character) -> bool
Definition numeric_util.h:69
auto count_multiples(const Minimum &minimum, const Maximum &maximum, const Multiplier &multiplier)
Definition numeric_util.h:191
auto abs(const T &value)
Definition numeric_util.h:273
constexpr auto uint_max
Definition numeric_util.h:232
constexpr auto is_within(const T &value, const std::int64_t lower, const std::int64_t higher) noexcept -> bool
Definition numeric_util.h:241
constexpr auto real_digits(Real value, std::uint64_t &point_position) -> Integer
Definition numeric_util.h:339