Skip to main content

malachite_base/num/conversion/string/options/
random.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::bools::random::{RandomBools, random_bools};
10use crate::num::conversion::string::options::{FromSciStringOptions, SciSizeOptions, ToSciOptions};
11use crate::num::random::geometric::{
12    GeometricRandomNaturalValues, GeometricRandomNegativeSigneds,
13    geometric_random_negative_signeds, geometric_random_unsigneds,
14};
15use crate::num::random::{RandomUnsignedInclusiveRange, random_unsigned_inclusive_range};
16use crate::random::Seed;
17use crate::rounding_modes::random::{RandomRoundingModes, random_rounding_modes};
18
19/// Generates random [`SciSizeOptions`]s.
20///
21/// This struct is created by [`random_sci_size_options`]; see its documentation for more.
22pub struct RandomSciSizeOptions {
23    bs: RandomBools,
24    xs: GeometricRandomNaturalValues<u64>,
25}
26
27impl Iterator for RandomSciSizeOptions {
28    type Item = SciSizeOptions;
29
30    fn next(&mut self) -> Option<SciSizeOptions> {
31        let x = self.xs.next().unwrap();
32        Some(if self.bs.next().unwrap() {
33            if x == 0 {
34                SciSizeOptions::Complete
35            } else {
36                SciSizeOptions::Precision(x)
37            }
38        } else {
39            SciSizeOptions::Scale(x)
40        })
41    }
42}
43
44/// Generates random [`SciSizeOptions`]s.
45///
46/// The scales and precisions are chosen from a geometric distribution whose mean is the ratio
47/// `m_size_numerator / m_size_denominator`.
48///
49/// # Panics
50/// Panics if `m_size_numerator` or `m_size_denominator` are zero, or, if after being reduced to
51/// lowest terms, their sum is greater than or equal to $2^{64}$.
52///
53/// The output length is infinite.
54pub fn random_sci_size_options(
55    seed: Seed,
56    m_size_numerator: u64,
57    m_size_denominator: u64,
58) -> RandomSciSizeOptions {
59    RandomSciSizeOptions {
60        bs: random_bools(seed.fork("bs")),
61        xs: geometric_random_unsigneds(seed.fork("xs"), m_size_numerator, m_size_denominator),
62    }
63}
64
65/// Generates random [`ToSciOptions`]s.
66///
67/// This struct is created by [`random_to_sci_options`]; see its documentation for more.
68pub struct RandomToSciOptions {
69    us: RandomUnsignedInclusiveRange<u8>,
70    rms: RandomRoundingModes,
71    sos: RandomSciSizeOptions,
72    is: GeometricRandomNegativeSigneds<i64>,
73    bs: RandomBools,
74}
75
76impl Iterator for RandomToSciOptions {
77    type Item = ToSciOptions;
78
79    fn next(&mut self) -> Option<ToSciOptions> {
80        Some(ToSciOptions {
81            base: self.us.next().unwrap(),
82            rounding_mode: self.rms.next().unwrap(),
83            size_options: self.sos.next().unwrap(),
84            neg_exp_threshold: self.is.next().unwrap(),
85            lowercase: self.bs.next().unwrap(),
86            e_lowercase: self.bs.next().unwrap(),
87            force_exponent_plus_sign: self.bs.next().unwrap(),
88            include_trailing_zeros: self.bs.next().unwrap(),
89        })
90    }
91}
92
93/// Generates random [`ToSciOptions`]s.
94///
95/// The scales, precisions, and the negative of the negative exponenet threshold are chosen from a
96/// geometric distribution whose mean is the ratio `m_size_numerator / m_size_denominator`.
97///
98/// # Panics
99/// Panics if `m_size_numerator` or `m_size_denominator` are zero, or, if after being reduced to
100/// lowest terms, their sum is greater than or equal to $2^{64}$.
101///
102/// The output length is infinite.
103pub fn random_to_sci_options(
104    seed: Seed,
105    m_size_numerator: u64,
106    m_size_denominator: u64,
107) -> RandomToSciOptions {
108    RandomToSciOptions {
109        us: random_unsigned_inclusive_range(seed.fork("us"), 2, 36),
110        rms: random_rounding_modes(seed.fork("rms")),
111        sos: random_sci_size_options(seed.fork("sos"), m_size_numerator, m_size_denominator),
112        is: geometric_random_negative_signeds(
113            seed.fork("is"),
114            m_size_numerator,
115            m_size_denominator,
116        ),
117        bs: random_bools(seed.fork("bs")),
118    }
119}
120
121/// Generates random [`FromSciStringOptions`]s.
122///
123/// This struct is created by [`random_from_sci_string_options`]; see its documentation for more.
124pub struct RandomFromSciStringOptions {
125    us: RandomUnsignedInclusiveRange<u8>,
126    rms: RandomRoundingModes,
127}
128
129impl Iterator for RandomFromSciStringOptions {
130    type Item = FromSciStringOptions;
131
132    fn next(&mut self) -> Option<FromSciStringOptions> {
133        Some(FromSciStringOptions {
134            base: self.us.next().unwrap(),
135            rounding_mode: self.rms.next().unwrap(),
136        })
137    }
138}
139
140/// Generates random [`FromSciStringOptions`]s.
141///
142/// The output length is infinite.
143pub fn random_from_sci_string_options(seed: Seed) -> RandomFromSciStringOptions {
144    RandomFromSciStringOptions {
145        us: random_unsigned_inclusive_range(seed.fork("us"), 2, 36),
146        rms: random_rounding_modes(seed.fork("rms")),
147    }
148}