27#include <system_error>
51 template <std::
signed_
integral U>
52 explicit(std::numeric_limits<T>::digits < std::numeric_limits<U>::digits)
constexpr basic_half_int(
53 basic_half_int<U> other)
noexcept(std::numeric_limits<T>::digits >= std::numeric_limits<U>::digits)
55 if constexpr (std::numeric_limits<T>::digits < std::numeric_limits<U>::digits)
57 if (other.
twice() <
static_cast<U
>(std::numeric_limits<T>::min()) ||
58 other.
twice() >
static_cast<U
>(std::numeric_limits<T>::max()))
60 throw std::overflow_error(
"basic_half_int conversion overflow");
63 twice_ =
static_cast<T
>(other.
twice());
81 constexpr auto twice() const -> T {
return twice_; }
85 constexpr auto is_integral() const ->
bool {
return (twice_ & T{1}) == 0; }
89 constexpr auto to_double() const ->
double {
return static_cast<double>(twice_) / 2.0; }
98 throw std::runtime_error(
"basic_half_int cannot be converted to an integer exactly");
100 return twice_ / T{2};
109 return twice_ / T{2};
117 twice_ += other.twice_;
126 twice_ -= other.twice_;
150 auto const old = *
this;
159 auto const old = *
this;
176 throw std::runtime_error(
"basic_half_int parse failed: empty string");
179 auto const slash =
text.find(
'/');
180 if (slash != std::string_view::npos)
182 auto const numerator = parse_integral<T>(
text.substr(0, slash));
183 auto const denominator =
text.substr(slash + 1);
184 if (denominator !=
"2")
186 throw std::runtime_error(
"basic_half_int parse failed: expected denominator 2");
188 return from_twice(numerator);
191 auto const dot =
text.find(
'.');
192 if (dot == std::string_view::npos)
197 auto const whole =
text.substr(0, dot);
198 auto const fractional =
text.substr(dot + 1);
199 if (fractional.empty())
203 if (fractional !=
"0" && fractional !=
"5")
205 throw std::runtime_error(
"basic_half_int parse failed: expected decimal .0 or .5");
208 auto const sign = (!whole.empty() && whole.front() ==
'-') ? T{-1} : T{1};
209 auto const twice_whole = checked_double(parse_integral<T>(whole));
210 auto const half = (fractional ==
"5") ? sign : T{0};
211 if (half < 0 && twice_whole == std::numeric_limits<T>::min())
213 throw std::overflow_error(
"basic_half_int doubled representation overflow");
215 return from_twice(twice_whole + half);
230 static constexpr auto checked_double(T
value) -> T
232 if (
value > std::numeric_limits<T>::max() / T{2} || value < std::numeric_limits<T>::min() / T{2})
234 throw std::overflow_error(
"basic_half_int doubled representation overflow");
242 template <std::
floating_po
int U>
static auto rounded_twice(U
value) -> T
244 auto const doubled = std::round(
static_cast<long double>(
value) * 2.0L);
245 if (doubled >
static_cast<long double>(std::numeric_limits<T>::max()) ||
246 doubled <
static_cast<long double>(std::numeric_limits<T>::min()))
248 throw std::overflow_error(
"basic_half_int rounded representation overflow");
250 return static_cast<T
>(doubled);
257 template <std::
integral Int>
static auto parse_integral(std::string_view
text) -> Int
261 throw std::runtime_error(
"basic_half_int parse failed: missing integer component");
264 auto const end =
text.data() +
text.size();
266 auto const [ptr, ec] = std::from_chars(
begin, end,
value);
267 if (ec != std::errc{} || ptr != end)
269 throw std::runtime_error(
"basic_half_int parse failed: invalid integer component");
284 static constexpr bool is_specialized =
true;
285 static constexpr bool is_signed =
true;
286 static constexpr bool is_integer =
false;
288 static constexpr bool is_bounded =
true;
289 static constexpr bool is_iec559 =
false;
290 static constexpr int radix = 2;
295 if (!
p.is_exact())
throw std::invalid_argument(
"half-integer arithmetic requires exact precision");
298 static constexpr bool has_infinity =
false;
299 static constexpr bool has_quiet_NaN =
false;
300 static constexpr bool has_signaling_NaN =
false;
332template <std::
signed_
integral T>
344template <std::
signed_
integral T>
357 return from_twice<T>(-
value.twice());
366template <std::
signed_
integral T, std::
integral U>
369 return from_twice<T>(lhs.twice() *
static_cast<T
>(rhs));
378template <std::
integral U, std::
signed_
integral T>
390template <std::
signed_
integral T, std::
floating_po
int U>
constexpr auto operator*(basic_half_int<T> lhs, U rhs) -> U
392 return static_cast<U
>(lhs.to_double()) * rhs;
401template <std::
floating_po
int U, std::
signed_
integral T>
constexpr auto operator*(U lhs, basic_half_int<T> rhs) -> U
403 return lhs *
static_cast<U
>(rhs.to_double());
413 return lhs.
to_double() * rhs.to_double();
424 return static_cast<U
>(lhs.to_double()) / rhs;
457 return value.to_int_assert();
466 if (
value.is_integral())
468 return std::to_string(
value.to_int_assert());
470 return std::to_string(
value.twice()) +
"/2";
479 if (
value.is_integral())
481 return std::to_string(
value.to_int_assert());
484 auto const whole =
value.twice() / T{2};
485 auto const fractional = (
value.twice() < 0 && whole == 0) ?
"-0.5" : std::to_string(whole) +
".5";
495 return 1 -
static_cast<int>((
value & T{1}) << 1);
504template <std::
signed_
integral T>
507 return (b >=
abs(a -
c)) && (b <= a +
c) && (a + b +
c).is_integral();
539 catch (std::runtime_error
const&)
541 in.setstate(std::ios::failbit);
548template <std::
signed_
integral T,
typename CharT>
struct std::formatter<
uni20::basic_half_int<T>, CharT>
550 constexpr auto parse(std::basic_format_parse_context<CharT>& ctx) {
return ctx.begin(); }
558template <std::
signed_
integral T>
struct std::hash<
uni20::basic_half_int<T>>
565 return std::hash<T>{}(
value.twice());
Exact arithmetic or an explicit binary working precision.
Definition core/precision.hpp:13
Signed value type that stores multiples of one half exactly.
Definition half_int.hpp:34
constexpr auto operator-=(basic_half_int other) -> basic_half_int &
Subtract another half-integer value.
Definition half_int.hpp:124
constexpr basic_half_int(T twice_value, twice_tag tag)
Construct directly from the doubled representation.
Definition half_int.hpp:77
constexpr auto operator--(int) -> basic_half_int
Postfix decrement by one.
Definition half_int.hpp:157
constexpr auto operator+=(basic_half_int other) -> basic_half_int &
Add another half-integer value.
Definition half_int.hpp:115
constexpr auto is_integral() const -> bool
Return whether the represented value is integral.
Definition half_int.hpp:85
constexpr auto operator++() -> basic_half_int &
Prefix increment by one.
Definition half_int.hpp:132
constexpr auto operator<=>(basic_half_int const &other) const =default
Compare two half-integer values.
constexpr auto to_double() const -> double
Convert to double.
Definition half_int.hpp:89
constexpr auto operator++(int) -> basic_half_int
Postfix increment by one.
Definition half_int.hpp:148
T value_type
Underlying signed storage type.
Definition half_int.hpp:37
basic_half_int(U value)
Construct by rounding a floating-point value to the nearest half-integer.
Definition half_int.hpp:72
constexpr auto to_int_assert() const -> T
Convert to the underlying integral type assuming exact integrality.
Definition half_int.hpp:106
static auto parse(std::string_view text) -> basic_half_int
Parse a textual half-integer representation.
Definition half_int.hpp:172
constexpr auto twice() const -> T
Return the doubled representation.
Definition half_int.hpp:81
constexpr auto to_int() const -> T
Convert to the underlying integral type.
Definition half_int.hpp:94
constexpr basic_half_int()=default
Construct the value zero.
constexpr basic_half_int(U value)
Construct from an integral value.
Definition half_int.hpp:68
constexpr auto operator--() -> basic_half_int &
Prefix decrement by one.
Definition half_int.hpp:140
bool empty() const noexcept
Return whether this document has no spans.
Definition presentation.cpp:1182
locale_t value
Definition data_table.cpp:49
presentation::styled_text text
Definition display.cpp:141
Definition data_table.cpp:8
Definition async/async.hpp:26
constexpr auto minus1pow(T value) -> int
Return (-1)^x for an integral exponent.
Definition half_int.hpp:493
constexpr auto operator*(basic_half_int< T > lhs, U rhs) -> basic_half_int< T >
Multiply a half-integer value by an integral scalar.
Definition half_int.hpp:367
auto operator<<(std::ostream &out, basic_half_int< T > value) -> std::ostream &
Stream a half-integer in integer or .5 decimal form.
Definition half_int.hpp:515
constexpr auto abs(basic_half_int< T > value) -> basic_half_int< T >
Return the absolute value of a half-integer.
Definition half_int.hpp:431
constexpr auto operator-(basic_half_int< T > lhs, basic_half_int< T > rhs) -> basic_half_int< T >
Subtract two half-integer values.
Definition half_int.hpp:345
constexpr auto from_twice(T twice_value) -> basic_half_int< T >
Construct a half-integer from its doubled representation.
Definition half_int.hpp:322
constexpr auto to_int_assert(basic_half_int< T > value) -> T
Convert a half-integer to its integral value assuming exact integrality.
Definition half_int.hpp:455
constexpr auto is_triangle(basic_half_int< T > a, basic_half_int< T > b, basic_half_int< T > c) -> bool
Return whether three nonnegative half-integers satisfy the triangle condition.
Definition half_int.hpp:505
auto to_string_fraction(basic_half_int< T > value) -> std::string
Format a half-integer as an integer or n/2.
Definition half_int.hpp:464
constexpr bool is_exact(detail::standard_complex< T > const &x)
A standard complex value is exact only when both components are exact.
Definition math.hpp:50
constexpr auto to_int(basic_half_int< T > value) -> T
Convert a half-integer to its integral value.
Definition half_int.hpp:449
auto to_string(basic_half_int< T > value) -> std::string
Format a half-integer as an integer or decimal .5.
Definition half_int.hpp:477
constexpr auto is_integral(basic_half_int< T > value) -> bool
Return whether a half-integer value is integral.
Definition half_int.hpp:440
auto operator>>(std::istream &in, basic_half_int< T > &value) -> std::istream &
Parse a half-integer from integer, .0, .5, or n/2 form.
Definition half_int.hpp:526
constexpr auto operator/(basic_half_int< T > lhs, U rhs) -> U
Divide a half-integer value by a floating-point scalar.
Definition half_int.hpp:422
auto operator()(uni20::basic_half_int< T > const &value) const noexcept -> std::size_t
Hash a half-integer by its doubled representation.
Definition half_int.hpp:563
Tag type used to construct directly from the doubled representation.
Definition half_int.hpp:41
static constexpr basic_half_int< T > max() noexcept
Greatest representable half-integer.
Definition half_int.hpp:309
static constexpr int digits() noexcept
Definition half_int.hpp:291
static constexpr int digits(Precision p)
Definition half_int.hpp:293
static constexpr basic_half_int< T > lowest() noexcept
Most negative representable half-integer.
Definition half_int.hpp:303
static constexpr int digits(basic_half_int< T > const &) noexcept
Definition half_int.hpp:292
Project-level numeric limits customization point.
Definition numeric_limits.hpp:16
#define DEBUG_PRECONDITION(cond,...)
Definition trace.hpp:648