Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
native_math.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "math_integer.hpp"
4#include <algorithm>
5#include <cmath>
6#include <cstdint>
7#include <stdexcept>
8#include <type_traits>
11
12namespace uni20::detail::native_math
13{
14template <class T>
15concept NativeReal = std::same_as<T, float> || std::same_as<T, double> || std::same_as<T, long double>
16#if UNI20_HAS_FLOAT128
17 || std::same_as<T, uni20::float128>
18#endif
19 ;
20
21template <NativeReal R> R round_even(R x)
22{
23 R lower = std::floor(x);
24 R fraction = x - lower;
25 if (fraction > R(0.5) || (fraction == R(0.5) && std::fmod(lower, R(2)) != R(0))) lower += R(1);
26 return lower == R(0) ? std::copysign(lower, x) : lower;
27}
28
29template <NativeReal R> frexp_result<R> frexp(R x)
30{
31 if (!std::isfinite(x) || x == R(0)) return {x, 0};
32 int exponent;
33 R fraction = std::frexp(x, &exponent);
34 return {fraction, exponent};
35}
36template <NativeReal R> modf_result<R> modf(R x)
37{
38 R integer;
39 R fraction = std::modf(x, &integer);
40 return {fraction, integer};
41}
42template <NativeReal R> remquo_result<R> remquo(R x, R y)
43{
44 if (!std::isfinite(x) || std::isnan(y) || y == R(0)) return {numeric_limits<R>::quiet_NaN(), 0};
45 int quotient = 0;
46 R remainder = std::remquo(x, y, &quotient);
47 return {remainder, quotient % 8};
48}
49template <NativeReal R> std::int64_t ilogb(R x)
50{
51 if (!std::isfinite(x) || x == R(0)) throw std::domain_error("ilogb requires a finite nonzero value");
52 return native_math::frexp(x).exponent - 1;
53}
54template <NativeReal R, MathInteger I> R ldexp(R x, I exponent)
55{
56 // Native floating exponents fit int. Clamping an even larger requested
57 // shift preserves overflow/underflow, including signed zero and infinity.
58 auto n = std::clamp<std::int64_t>(math_integer(exponent), numeric_limits<int>::min(), numeric_limits<int>::max());
59 return std::ldexp(x, static_cast<int>(n));
60}
61template <NativeReal R, MathInteger I> R scalbn(R x, I exponent) { return native_math::ldexp(x, exponent); }
62
63template <NativeReal R, MathInteger I> R pown(R x, I value)
64{
65 auto exponent = math_integer(value);
66 std::uint64_t magnitude = exponent < 0 ? std::uint64_t(0) - std::uint64_t(exponent) : std::uint64_t(exponent);
67 R result(1);
68 if (exponent < 0) x = result / x;
69 while (magnitude)
70 {
71 if (magnitude & 1) result *= x;
72 magnitude >>= 1;
73 if (magnitude) x *= x;
74 }
75 return result;
76}
77template <NativeReal R, MathInteger I> R rootn(R x, I value)
78{
79 auto degree = math_integer(value);
80 if (degree == 0) return numeric_limits<R>::quiet_NaN();
81 if (degree == 1) return x;
82 if (degree == -1) return R(1) / x;
83 bool odd = degree % 2 != 0;
84 if (std::signbit(x) && !odd && x != R(0)) return numeric_limits<R>::quiet_NaN();
85 R magnitude = std::abs(x);
86 R result;
87 if (degree == 2 || degree == -2)
88 result = std::sqrt(magnitude);
89 else if (degree == 3 || degree == -3)
90 result = std::cbrt(magnitude);
91 else
92 return odd ? std::copysign(std::pow(magnitude, R(1) / R(degree)), x) : std::pow(magnitude, R(1) / R(degree));
93 if (degree < 0) result = R(1) / result;
94 return odd ? std::copysign(result, x) : result;
95}
96template <NativeReal R> sincos_result<R> sincos(R x) { return {std::sin(x), std::cos(x)}; }
97template <NativeReal R> sinhcosh_result<R> sinhcosh(R x) { return {std::sinh(x), std::cosh(x)}; }
98
99template <NativeReal R, NativeReal S> R copysign(R magnitude, S sign)
100{
101 return std::copysign(magnitude, std::signbit(sign) ? R(-1) : R(1));
102}
103template <NativeReal R, NativeReal S> auto fmin(R a, S b)
104{
105 auto result = std::fmin(a, b);
106 if (a == 0 && b == 0) return std::copysign(result, decltype(result)((std::signbit(a) || std::signbit(b)) ? -1 : 1));
107 return result;
108}
109template <NativeReal R, NativeReal S> auto fmax(R a, S b)
110{
111 auto result = std::fmax(a, b);
112 if (a == 0 && b == 0) return std::copysign(result, decltype(result)((std::signbit(a) && std::signbit(b)) ? -1 : 1));
113 return result;
114}
115template <NativeReal R> R next_up(R x) { return std::nextafter(x, numeric_limits<R>::infinity()); }
116template <NativeReal R> R next_down(R x) { return std::nextafter(x, -numeric_limits<R>::infinity()); }
117template <NativeReal R, NativeReal S> R nextafter(R x, S direction)
118{
119 if (std::isnan(x) || std::isnan(direction)) return numeric_limits<R>::quiet_NaN();
120 if (x == direction) return native_math::copysign(x, direction);
121 return x < direction ? native_math::next_up(x) : native_math::next_down(x);
122}
123} // namespace uni20::detail::native_math
locale_t value
Definition data_table.cpp:49
Definition qnum.hpp:403
DiagnosticMagnitude< R > magnitude(R const &value)
Definition gmres_diagnostics.hpp:98
constexpr detail::scalar_math::nextafter_fn nextafter
Adjacent value on the first operand grid toward the direction operand.
Definition math.hpp:549
constexpr detail::scalar_math::pown_fn pown
Integer power with scalar-specific rounding.
Definition math.hpp:529
constexpr detail::scalar_math::remquo_fn remquo
Nearest-even remainder and signed low three quotient bits.
Definition math.hpp:539
constexpr detail::scalar_math::scalbn_fn scalbn
Binary scaling with a signed 64-bit exponent.
Definition math.hpp:533
constexpr detail::scalar_math::modf_fn modf
Signed fractional and integral parts as an owning result.
Definition math.hpp:537
constexpr detail::scalar_math::ldexp_fn ldexp
Multiply by a power of two using the scalar's exponent interface.
Definition math.hpp:511
constexpr detail::scalar_math::ilogb_fn ilogb
Binary exponent of a finite nonzero value; throws otherwise.
Definition math.hpp:545
constexpr detail::scalar_math::sinhcosh_fn sinhcosh
Hyperbolic sine and cosine at one input.
Definition math.hpp:543
constexpr detail::scalar_math::next_up_fn next_up
Adjacent value toward positive infinity.
Definition math.hpp:551
constexpr detail::scalar_math::rootn_fn rootn
Real integer-order root; negative orders give reciprocal roots.
Definition math.hpp:531
constexpr detail::scalar_math::fmin_fn fmin
Minimum, preferring the numeric operand over a NaN.
Definition math.hpp:559
constexpr detail::scalar_math::next_down_fn next_down
Adjacent value toward negative infinity.
Definition math.hpp:553
constexpr detail::scalar_math::fmax_fn fmax
Maximum, preferring the numeric operand over a NaN.
Definition math.hpp:561
constexpr detail::scalar_math::sincos_fn sincos
Sine and cosine at one input.
Definition math.hpp:541
constexpr detail::scalar_math::round_even_fn round_even
Nearest integer with ties to even.
Definition math.hpp:527
constexpr detail::scalar_math::frexp_fn frexp
Binary fraction and exponent as an owning result.
Definition math.hpp:535
constexpr detail::scalar_math::copysign_fn copysign
Copy the sign while retaining the magnitude operand type and precision.
Definition math.hpp:547
auto degree(QNum const &q) -> int
Return the integral degree of a quantum number.
Definition qnum.hpp:270
exact_rational pow(X const &base, Y const &power)
Evaluate a rational power exactly when its real result is rational.
Definition exact_rational.hpp:337
mpreal remainder(mpreal const &a, mpreal const &b)
Nearest-even-quotient remainder; exact operands retain exact rational results.
Definition mpreal_functions.hpp:534