1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use super::AncDec128;
use crate::util::{pow10_128, pow10_256};
use crate::wide::{divmod_u256, isqrt_u512, mul_u256, mul_wide};
impl AncDec128 {
/// Returns the absolute value.
#[inline(always)]
pub fn abs(&self) -> Self {
Self {
neg: false,
..*self
}
}
/// Returns the sign: `1` for positive, `-1` for negative, `0` for zero.
#[inline(always)]
pub fn signum(&self) -> Self {
if self.is_zero() {
Self::ZERO
} else if self.neg {
Self {
int: 1,
frac: 0,
scale: 0,
neg: true,
}
} else {
Self::ONE
}
}
/// Returns `true` if the value is strictly positive.
#[inline(always)]
pub fn is_positive(&self) -> bool {
!self.neg && !self.is_zero()
}
/// Returns `true` if the value is strictly negative.
#[inline(always)]
pub fn is_negative(&self) -> bool {
self.neg && !self.is_zero()
}
/// Returns `true` if the value is zero.
#[inline(always)]
pub fn is_zero(&self) -> bool {
self.int == 0 && self.frac == 0
}
/// Returns the smaller of `self` and `other`.
#[inline(always)]
pub fn min(self, other: Self) -> Self {
if self <= other {
self
} else {
other
}
}
/// Returns the larger of `self` and `other`.
#[inline(always)]
pub fn max(self, other: Self) -> Self {
if self >= other {
self
} else {
other
}
}
/// Clamps the value to the range `[min, max]`.
#[inline(always)]
pub fn clamp(self, min: Self, max: Self) -> Self {
if self < min {
min
} else if self > max {
max
} else {
self
}
}
/// Returns the square root with 37 fractional digits of precision. Panics if negative.
pub fn sqrt(&self) -> Self {
assert!(!self.neg || self.is_zero(), "square root of negative number");
if self.is_zero() {
return Self::ZERO;
}
// combined = int * 10^scale + frac as u256
let (c_hi, c_lo) = mul_wide(self.int, pow10_128(self.scale));
let (c_lo, carry) = c_lo.overflowing_add(self.frac);
let combined = (c_hi + carry as u128, c_lo);
// N = combined * 10^(74 - scale) → u512
// isqrt(N) = floor(sqrt(value) * 10^37)
let multiplier = pow10_256(74 - self.scale);
let (w3, w2, w1, w0) = mul_u256(combined, multiplier);
let (r_hi, r_lo) = isqrt_u512(w3, w2, w1, w0);
let scale37 = pow10_128(37);
let ((_, q), r) = divmod_u256(r_hi, r_lo, scale37);
Self { int: q, frac: r, scale: 37, neg: false }
}
/// Raises `self` to the power `n` using binary exponentiation. Supports negative exponents.
pub fn pow(&self, n: i32) -> Self {
if n == 0 {
return Self::ONE;
}
let mut base = if n < 0 {
assert!(!self.is_zero(), "division by zero in pow with negative exponent");
Self::ONE.div(self)
} else {
*self
};
let mut exp = n.unsigned_abs();
let mut result = Self::ONE;
while exp > 0 {
if exp % 2 == 1 {
result = result.mul(&base);
}
base = base.mul(&base);
exp /= 2;
}
result
}
}