Skip to main content

zenith_float_num/
defs.rs

1//! Definitions.
2
3use 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/// A word.
13#[cfg(not(target_pointer_width = "32"))]
14pub type Word = u64;
15
16/// Doubled word.
17#[cfg(not(target_pointer_width = "32"))]
18pub type DoubleWord = u128;
19
20/// Word with sign.
21#[cfg(not(target_pointer_width = "32"))]
22pub type SignedWord = i128;
23
24/// A word.
25#[cfg(target_pointer_width = "32")]
26pub type Word = u32;
27
28/// Doubled word.
29#[cfg(target_pointer_width = "32")]
30pub type DoubleWord = u64;
31
32/// Word with sign.
33#[cfg(target_pointer_width = "32")]
34pub type SignedWord = i64;
35
36// Word-sized values are used as indices throughout the implementation.
37const _: [(); 1] = [(); (core::mem::size_of::<Word>() <= core::mem::size_of::<usize>()) as usize];
38
39/// An exponent.
40pub type Exponent = i32;
41
42/// Maximum exponent value.
43#[cfg(not(target_pointer_width = "32"))]
44pub const EXPONENT_MAX: Exponent = Exponent::MAX;
45
46/// Maximum exponent value.
47#[cfg(target_pointer_width = "32")]
48pub const EXPONENT_MAX: Exponent = Exponent::MAX / 4;
49
50/// Minimum exponent value.
51#[cfg(not(target_pointer_width = "32"))]
52pub const EXPONENT_MIN: Exponent = Exponent::MIN;
53
54/// Minimum exponent value.
55#[cfg(target_pointer_width = "32")]
56pub const EXPONENT_MIN: Exponent = Exponent::MIN / 4;
57
58/// Maximum value of a word.
59pub const WORD_MAX: Word = Word::MAX;
60
61/// Base of words.
62pub const WORD_BASE: DoubleWord = WORD_MAX as DoubleWord + 1;
63
64/// Size of a word in bits.
65pub const WORD_BIT_SIZE: usize = core::mem::size_of::<Word>() * 8;
66
67/// Cases per `proptest` property under `cargo test` (no `mpfr-tests` required).
68pub const PROPTEST_CASES: u32 = 1000;
69
70/// Word with the most significant bit set.
71pub const WORD_SIGNIFICANT_BIT: Word = WORD_MAX << (WORD_BIT_SIZE - 1);
72
73/// Default precision.
74pub const DEFAULT_P: usize = 128;
75
76/// The size of exponent type in bits.
77pub const EXPONENT_BIT_SIZE: usize = core::mem::size_of::<Exponent>() * 8;
78
79/// Sign.
80#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
81pub enum Sign {
82    /// Negative.
83    Neg = -1,
84
85    /// Positive.
86    Pos = 1,
87}
88
89impl Sign {
90    /// Changes the sign to the opposite.
91    pub fn invert(&self) -> Self {
92        match *self {
93            Sign::Pos => Sign::Neg,
94            Sign::Neg => Sign::Pos,
95        }
96    }
97
98    /// Returns true if `self` is positive.
99    pub fn is_positive(&self) -> bool {
100        *self == Sign::Pos
101    }
102
103    /// Returns true if `self` is negative.
104    pub fn is_negative(&self) -> bool {
105        *self == Sign::Neg
106    }
107
108    /// Returns 1 for the positive sign and -1 for the negative sign.
109    pub fn to_int(&self) -> i8 {
110        *self as i8
111    }
112}
113
114/// Possible errors.
115#[derive(Debug, Clone, Copy)]
116pub enum Error {
117    /// The exponent value becomes greater than the upper limit of the range of exponent values.
118    ExponentOverflow(Sign),
119
120    /// Divizor is zero.
121    DivisionByZero,
122
123    /// Invalid argument.
124    InvalidArgument,
125
126    /// Correct-rounding retries exhausted (`MAX_PREC_RETRY`). Not a domain error.
127    PrecisionRetryExhausted,
128
129    /// Memory allocation error.
130    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/// Radix for parse/format (bases 2 through 36).
181#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
182pub struct Radix(u8);
183
184#[allow(non_upper_case_globals)]
185impl Radix {
186    /// Binary (base 2).
187    pub const Bin: Radix = Radix(2);
188    /// Octal (base 8).
189    pub const Oct: Radix = Radix(8);
190    /// Decimal (base 10).
191    pub const Dec: Radix = Radix(10);
192    /// Hexadecimal (base 16).
193    pub const Hex: Radix = Radix(16);
194
195    /// Creates a radix in the inclusive range 2..=36.
196    ///
197    /// ## Errors
198    ///
199    ///  - InvalidArgument: `base` is outside 2..=36.
200    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    /// Returns the numeric base.
209    pub const fn value(self) -> u8 {
210        self.0
211    }
212
213    /// Returns `log2(base)` when the base is a power of two.
214    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    /// Whether the scientific exponent must use `_e` (digit `e` appears in mantissa digits).
224    pub const fn uses_underscore_exponent(self) -> bool {
225        self.0 > 10
226    }
227
228    /// Approximate bits per digit (for buffer sizing).
229    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/// Rounding modes.
248#[derive(Eq, PartialEq, Debug, Copy, Clone)]
249pub enum RoundingMode {
250    /// Skip rounding operation.
251    None = 1,
252
253    /// Round half toward positive infinity.
254    Up = 2,
255
256    /// Round half toward negative infinity.
257    Down = 4,
258
259    /// Round half toward zero.
260    ToZero = 8,
261
262    /// Round half away from zero.
263    FromZero = 16,
264
265    /// Round half to even.
266    ToEven = 32,
267
268    /// Round half to odd.
269    ToOdd = 64,
270}