1use core::alloc::LayoutError;
4use core::fmt::Display;
5
6#[cfg(feature = "std")]
7use std::collections::TryReserveError;
8
9#[cfg(not(feature = "std"))]
10use alloc::collections::TryReserveError;
11
12#[cfg(not(target_pointer_width = "32"))]
14pub type Word = u64;
15
16#[cfg(not(target_pointer_width = "32"))]
18pub type DoubleWord = u128;
19
20#[cfg(not(target_pointer_width = "32"))]
22pub type SignedWord = i128;
23
24#[cfg(target_pointer_width = "32")]
26pub type Word = u32;
27
28#[cfg(target_pointer_width = "32")]
30pub type DoubleWord = u64;
31
32#[cfg(target_pointer_width = "32")]
34pub type SignedWord = i64;
35
36const _: [(); 1] = [(); (core::mem::size_of::<Word>() <= core::mem::size_of::<usize>()) as usize];
38
39pub type Exponent = i32;
41
42#[cfg(not(target_pointer_width = "32"))]
44pub const EXPONENT_MAX: Exponent = Exponent::MAX;
45
46#[cfg(target_pointer_width = "32")]
48pub const EXPONENT_MAX: Exponent = Exponent::MAX / 4;
49
50#[cfg(not(target_pointer_width = "32"))]
52pub const EXPONENT_MIN: Exponent = Exponent::MIN;
53
54#[cfg(target_pointer_width = "32")]
56pub const EXPONENT_MIN: Exponent = Exponent::MIN / 4;
57
58pub const WORD_MAX: Word = Word::MAX;
60
61pub const WORD_BASE: DoubleWord = WORD_MAX as DoubleWord + 1;
63
64pub const WORD_BIT_SIZE: usize = core::mem::size_of::<Word>() * 8;
66
67pub const PROPTEST_CASES: u32 = 1000;
69
70pub const WORD_SIGNIFICANT_BIT: Word = WORD_MAX << (WORD_BIT_SIZE - 1);
72
73pub const DEFAULT_P: usize = 128;
75
76pub const EXPONENT_BIT_SIZE: usize = core::mem::size_of::<Exponent>() * 8;
78
79#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
81pub enum Sign {
82 Neg = -1,
84
85 Pos = 1,
87}
88
89impl Sign {
90 pub fn invert(&self) -> Self {
92 match *self {
93 Sign::Pos => Sign::Neg,
94 Sign::Neg => Sign::Pos,
95 }
96 }
97
98 pub fn is_positive(&self) -> bool {
100 *self == Sign::Pos
101 }
102
103 pub fn is_negative(&self) -> bool {
105 *self == Sign::Neg
106 }
107
108 pub fn to_int(&self) -> i8 {
110 *self as i8
111 }
112}
113
114#[derive(Debug, Clone, Copy)]
116pub enum Error {
117 ExponentOverflow(Sign),
119
120 DivisionByZero,
122
123 InvalidArgument,
125
126 PrecisionRetryExhausted,
128
129 MemoryAllocation,
131}
132
133#[cfg(feature = "std")]
134impl std::error::Error for Error {
135 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
136 None
137 }
138}
139
140impl Display for Error {
141 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
142 let repr = match self {
143 Error::ExponentOverflow(s) => {
144 if s.is_positive() {
145 "positive overflow"
146 } else {
147 "negative overflow"
148 }
149 }
150 Error::DivisionByZero => "division by zero",
151 Error::InvalidArgument => "invalid argument",
152 Error::PrecisionRetryExhausted => "precision retry exhausted",
153 Error::MemoryAllocation => "memory allocation failure",
154 };
155 f.write_str(repr)
156 }
157}
158
159impl PartialEq for Error {
160 fn eq(&self, other: &Self) -> bool {
161 match (self, other) {
162 (Self::ExponentOverflow(l0), Self::ExponentOverflow(r0)) => l0 == r0,
163 _ => core::mem::discriminant(self) == core::mem::discriminant(other),
164 }
165 }
166}
167
168impl From<TryReserveError> for Error {
169 fn from(_: TryReserveError) -> Self {
170 Error::MemoryAllocation
171 }
172}
173
174impl From<LayoutError> for Error {
175 fn from(_: LayoutError) -> Self {
176 Error::MemoryAllocation
177 }
178}
179
180#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
182pub struct Radix(u8);
183
184#[allow(non_upper_case_globals)]
185impl Radix {
186 pub const Bin: Radix = Radix(2);
188 pub const Oct: Radix = Radix(8);
190 pub const Dec: Radix = Radix(10);
192 pub const Hex: Radix = Radix(16);
194
195 pub fn try_new(base: u8) -> Result<Self, Error> {
201 if (2..=36).contains(&base) {
202 Ok(Radix(base))
203 } else {
204 Err(Error::InvalidArgument)
205 }
206 }
207
208 pub const fn value(self) -> u8 {
210 self.0
211 }
212
213 pub const fn commensurable_shift(self) -> Option<usize> {
215 let b = self.0;
216 if b.is_power_of_two() {
217 Some(b.trailing_zeros() as usize)
218 } else {
219 None
220 }
221 }
222
223 pub const fn uses_underscore_exponent(self) -> bool {
225 self.0 > 10
226 }
227
228 pub fn bits_per_digit(self) -> usize {
230 match self.0 {
231 2 => 1,
232 8 => 3,
233 10 => 3,
234 16 => 4,
235 b if b.is_power_of_two() => b.trailing_zeros() as usize,
236 _ => 4,
237 }
238 }
239}
240
241impl From<Radix> for u8 {
242 fn from(r: Radix) -> u8 {
243 r.0
244 }
245}
246
247#[derive(Eq, PartialEq, Debug, Copy, Clone)]
249pub enum RoundingMode {
250 None = 1,
252
253 Up = 2,
255
256 Down = 4,
258
259 ToZero = 8,
261
262 FromZero = 16,
264
265 ToEven = 32,
267
268 ToOdd = 64,
270}