// Copyright © 2026 Mikhail Hogrefe
//
// This file is part of Malachite.
//
// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.

use crate::arithmetic::log_base::{rational_log_base, rational_log_base_of_rational};
use crate::arithmetic::log_base_1_plus_x::log_base_1_plus_x_rational;
use crate::arithmetic::log_base_10::float_is_power_of_10;
use crate::arithmetic::log_base_float_base::log_base_float_base_rational;
use crate::arithmetic::log_base_float_base_1_plus_x::log_base_float_base_1_plus_x_rational;
use crate::arithmetic::log_base_rational_base::rational_log_base_rational_base;
use crate::arithmetic::log_base_rational_base_1_plus_x::rational_log_base_rational_base_1_plus_x;
use crate::arithmetic::log_base_rational_float_base::log_base_rational_float_base_rational;
use crate::arithmetic::log_base_rational_rational_base::rational_log_base_rational_rational_base;
use crate::exhaustive::{
    ExhaustivePositiveFiniteFloatsGenerator, ExhaustivePositiveFloatsWithSciExponent,
    exhaustive_finite_floats, exhaustive_floats, exhaustive_non_negative_finite_floats,
    exhaustive_nonzero_finite_floats, exhaustive_positive_finite_floats,
    exhaustive_positive_floats_with_precision, exhaustive_positive_floats_with_sci_exponent,
};
use crate::test_util::extra_variadic::{
    exhaustive_triples_from_single, exhaustive_triples_xxy, exhaustive_triples_xxy_custom_output,
};
use crate::{Float, significand_bits};
use alloc::vec::IntoIter;
use core::cmp::Ordering::*;
use malachite_base::iterators::bit_distributor::BitDistributorOutputType;
use malachite_base::num::arithmetic::traits::{
    CheckedLogBase, CheckedLogBase2, IsPowerOf2, Reciprocal, Square,
};
use malachite_base::num::basic::floats::PrimitiveFloat;
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::signeds::PrimitiveSigned;
use malachite_base::num::basic::traits::{Infinity, NaN, NegativeInfinity, NegativeZero, Zero};
use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
use malachite_base::num::conversion::traits::{ConvertibleFrom, ExactFrom, SaturatingFrom};
use malachite_base::num::exhaustive::{
    exhaustive_nonzero_signeds, exhaustive_positive_primitive_ints, exhaustive_primitive_floats,
    exhaustive_signeds, exhaustive_unsigneds, primitive_int_increasing_inclusive_range,
};
use malachite_base::num::iterators::{BitDistributorSequence, bit_distributor_sequence};
use malachite_base::num::logic::traits::{NotAssign, SignificantBits};
use malachite_base::orderings::exhaustive::exhaustive_orderings;
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_base::rounding_modes::exhaustive::exhaustive_rounding_modes;
use malachite_base::test_util::generators::common::{It, reshape_2_1_to_3, reshape_3_1_to_4};
use malachite_base::test_util::generators::exhaustive_pairs_big_tiny;
use malachite_base::tuples::exhaustive::{
    ExhaustiveDependentPairs, ExhaustiveDependentPairsYsGenerator, exhaustive_dependent_pairs,
};
use malachite_base::tuples::exhaustive::{
    exhaustive_pairs, exhaustive_pairs_from_single, exhaustive_triples,
    exhaustive_triples_custom_output, exhaustive_triples_xyy, lex_pairs,
};
use malachite_nz::integer::Integer;
use malachite_nz::integer::exhaustive::exhaustive_integers;
use malachite_nz::natural::Natural;
use malachite_nz::natural::exhaustive::exhaustive_naturals;
use malachite_nz::platform::Limb;
use malachite_q::Rational;
use malachite_q::exhaustive::{exhaustive_non_negative_rationals, exhaustive_rationals};
use std::cmp::{Ordering, max};
use std::iter::Chain;
use std::mem::swap;

// -- Float --

pub fn exhaustive_float_gen() -> It<Float> {
    Box::new(exhaustive_floats())
}

pub fn exhaustive_float_gen_var_1() -> It<Float> {
    Box::new(exhaustive_positive_finite_floats())
}

pub fn exhaustive_float_gen_var_2() -> It<Float> {
    Box::new(exhaustive_floats().filter(|f| !f.is_nan()))
}

pub fn exhaustive_float_gen_var_3() -> It<Float> {
    Box::new(exhaustive_nonzero_finite_floats())
}

pub fn exhaustive_float_gen_var_4() -> It<Float> {
    Box::new(exhaustive_finite_floats())
}

pub fn exhaustive_float_gen_var_5() -> It<Float> {
    Box::new(exhaustive_non_negative_finite_floats())
}

pub fn exhaustive_float_gen_var_6() -> It<Float> {
    Box::new(exhaustive_floats_with_precision_inclusive_range(
        1,
        Limb::WIDTH - 1,
    ))
}

pub fn exhaustive_float_gen_var_7() -> It<Float> {
    Box::new(exhaustive_positive_floats_with_precision(Limb::WIDTH))
}

pub fn exhaustive_float_gen_var_8() -> It<Float> {
    Box::new(exhaustive_floats_with_precision_inclusive_range(
        Limb::WIDTH + 1,
        (Limb::WIDTH << 1) - 1,
    ))
}

pub fn exhaustive_float_gen_var_9() -> It<Float> {
    Box::new(exhaustive_positive_floats_with_precision(Limb::WIDTH << 1))
}

pub fn exhaustive_float_gen_var_10() -> It<Float> {
    Box::new(exhaustive_floats_with_precision_inclusive_range(
        (Limb::WIDTH << 1) + 1,
        Limb::WIDTH * 3 - 1,
    ))
}

pub fn exhaustive_float_gen_var_11() -> It<Float> {
    Box::new(exhaustive_floats_with_precision_inclusive_range(
        (Limb::WIDTH << 1) + 1,
        u64::MAX,
    ))
}

pub fn exhaustive_float_gen_var_12() -> It<Float> {
    Box::new(exhaustive_extreme_floats())
}

pub fn exhaustive_float_gen_var_13() -> It<Float> {
    Box::new(exhaustive_extreme_nonzero_finite_floats())
}

pub fn exhaustive_float_gen_var_14() -> It<Float> {
    Box::new(exhaustive_extreme_floats().filter(|f| !f.is_nan()))
}

pub fn exhaustive_float_gen_var_15() -> It<Float> {
    Box::new(exhaustive_floats().filter(|x| *x > 0u32))
}

#[derive(Clone, Debug)]
pub struct ExhaustiveExtremeExponents {
    counter: bool,
    i: i32,
    end_counter: u8,
}

impl Iterator for ExhaustiveExtremeExponents {
    type Item = i32;

    fn next(&mut self) -> Option<i32> {
        if self.i == 2 {
            return match self.end_counter {
                0 => {
                    self.end_counter = 1;
                    Some(-2)
                }
                1 => {
                    self.end_counter = 2;
                    Some(-1)
                }
                2 => {
                    self.end_counter = 3;
                    Some(0)
                }
                _ => None,
            };
        }
        Some(if self.counter {
            self.counter = false;
            self.i - 2
        } else {
            self.counter = true;
            self.i -= 1;
            -self.i - 1
        })
    }
}

pub const fn exhaustive_extreme_exponents() -> ExhaustiveExtremeExponents {
    ExhaustiveExtremeExponents {
        counter: true,
        i: Float::MAX_EXPONENT + 1,
        end_counter: 0,
    }
}

#[derive(Clone, Debug)]
struct ExhaustiveMixedExtremeExponents {
    first: bool,
    counter: u8,
    low: i32,
    high: i32,
    end_counter: u8,
}

impl Iterator for ExhaustiveMixedExtremeExponents {
    type Item = i32;

    fn next(&mut self) -> Option<i32> {
        if self.low == self.high {
            return match self.end_counter {
                0 => {
                    self.end_counter = 1;
                    Some(-self.high)
                }
                1 => {
                    self.end_counter = 2;
                    Some(-self.high - 1)
                }
                _ => None,
            };
        }
        Some(if self.first {
            self.first = false;
            0
        } else {
            match self.counter {
                0 => {
                    self.counter = 1;
                    self.low
                }
                1 => {
                    self.counter = 2;
                    self.low += 1;
                    -self.low + 1
                }
                2 => {
                    self.counter = 3;
                    self.high - 1
                }
                3 => {
                    self.counter = 0;
                    self.high -= 1;
                    -self.high - 2
                }
                _ => unreachable!(),
            }
        })
    }
}

const fn exhaustive_mixed_extreme_exponents() -> ExhaustiveMixedExtremeExponents {
    ExhaustiveMixedExtremeExponents {
        first: true,
        counter: 0,
        low: 1,
        high: Float::MAX_EXPONENT,
        end_counter: 0,
    }
}

#[inline]
fn exhaustive_extreme_positive_finite_floats_helper() -> ExhaustiveDependentPairs<
    i32,
    Float,
    BitDistributorSequence,
    ExhaustivePositiveFiniteFloatsGenerator,
    ExhaustiveExtremeExponents,
    ExhaustivePositiveFloatsWithSciExponent,
> {
    exhaustive_dependent_pairs(
        bit_distributor_sequence(
            BitDistributorOutputType::normal(1),
            BitDistributorOutputType::normal(1),
        ),
        exhaustive_extreme_exponents(),
        ExhaustivePositiveFiniteFloatsGenerator,
    )
}

#[derive(Clone, Debug)]
struct ExhaustiveExtremePositiveFiniteFloats(
    ExhaustiveDependentPairs<
        i32,
        Float,
        BitDistributorSequence,
        ExhaustivePositiveFiniteFloatsGenerator,
        ExhaustiveExtremeExponents,
        ExhaustivePositiveFloatsWithSciExponent,
    >,
);

impl Iterator for ExhaustiveExtremePositiveFiniteFloats {
    type Item = Float;

    #[inline]
    fn next(&mut self) -> Option<Float> {
        self.0.next().map(|p| p.1)
    }
}

#[inline]
fn exhaustive_extreme_positive_finite_floats() -> ExhaustiveExtremePositiveFiniteFloats {
    ExhaustiveExtremePositiveFiniteFloats(exhaustive_extreme_positive_finite_floats_helper())
}

#[derive(Clone, Debug)]
struct ExhaustiveExtremeNonzeroFiniteFloats {
    toggle: bool,
    xs: ExhaustiveExtremePositiveFiniteFloats,
    x: Float,
}

impl Iterator for ExhaustiveExtremeNonzeroFiniteFloats {
    type Item = Float;

    #[inline]
    fn next(&mut self) -> Option<Float> {
        self.toggle.not_assign();
        Some(if self.toggle {
            self.x = self.xs.next().unwrap();
            self.x.clone()
        } else {
            let mut out = Float::NAN;
            swap(&mut out, &mut self.x);
            -out
        })
    }
}

#[inline]
fn exhaustive_extreme_nonzero_finite_floats() -> ExhaustiveExtremeNonzeroFiniteFloats {
    ExhaustiveExtremeNonzeroFiniteFloats {
        toggle: false,
        xs: exhaustive_extreme_positive_finite_floats(),
        x: Float::NAN,
    }
}

type ExhaustiveExtremeFloats = Chain<IntoIter<Float>, ExhaustiveExtremeNonzeroFiniteFloats>;

#[inline]
fn exhaustive_extreme_floats() -> ExhaustiveExtremeFloats {
    alloc::vec![
        Float::NAN,
        Float::INFINITY,
        Float::NEGATIVE_INFINITY,
        Float::ZERO,
        Float::NEGATIVE_ZERO
    ]
    .into_iter()
    .chain(exhaustive_extreme_nonzero_finite_floats())
}

#[inline]
fn exhaustive_mixed_extreme_positive_finite_floats_helper() -> ExhaustiveDependentPairs<
    i32,
    Float,
    BitDistributorSequence,
    ExhaustivePositiveFiniteFloatsGenerator,
    ExhaustiveMixedExtremeExponents,
    ExhaustivePositiveFloatsWithSciExponent,
> {
    exhaustive_dependent_pairs(
        bit_distributor_sequence(
            BitDistributorOutputType::normal(1),
            BitDistributorOutputType::normal(1),
        ),
        exhaustive_mixed_extreme_exponents(),
        ExhaustivePositiveFiniteFloatsGenerator,
    )
}

#[derive(Clone, Debug)]
struct ExhaustiveMixedExtremePositiveFiniteFloats(
    ExhaustiveDependentPairs<
        i32,
        Float,
        BitDistributorSequence,
        ExhaustivePositiveFiniteFloatsGenerator,
        ExhaustiveMixedExtremeExponents,
        ExhaustivePositiveFloatsWithSciExponent,
    >,
);

impl Iterator for ExhaustiveMixedExtremePositiveFiniteFloats {
    type Item = Float;

    #[inline]
    fn next(&mut self) -> Option<Float> {
        self.0.next().map(|p| p.1)
    }
}

#[inline]
fn exhaustive_mixed_extreme_positive_finite_floats() -> ExhaustiveMixedExtremePositiveFiniteFloats {
    ExhaustiveMixedExtremePositiveFiniteFloats(
        exhaustive_mixed_extreme_positive_finite_floats_helper(),
    )
}

#[derive(Clone, Debug)]
struct ExhaustiveMixedExtremeNonzeroFiniteFloats {
    toggle: bool,
    xs: ExhaustiveMixedExtremePositiveFiniteFloats,
    x: Float,
}

impl Iterator for ExhaustiveMixedExtremeNonzeroFiniteFloats {
    type Item = Float;

    #[inline]
    fn next(&mut self) -> Option<Float> {
        self.toggle.not_assign();
        Some(if self.toggle {
            self.x = self.xs.next().unwrap();
            self.x.clone()
        } else {
            let mut out = Float::NAN;
            swap(&mut out, &mut self.x);
            -out
        })
    }
}

#[inline]
fn exhaustive_mixed_extreme_nonzero_finite_floats() -> ExhaustiveMixedExtremeNonzeroFiniteFloats {
    ExhaustiveMixedExtremeNonzeroFiniteFloats {
        toggle: false,
        xs: exhaustive_mixed_extreme_positive_finite_floats(),
        x: Float::NAN,
    }
}

type ExhaustiveMixedExtremeFloats =
    Chain<IntoIter<Float>, ExhaustiveMixedExtremeNonzeroFiniteFloats>;

#[inline]
fn exhaustive_mixed_extreme_floats() -> ExhaustiveMixedExtremeFloats {
    alloc::vec![
        Float::NAN,
        Float::INFINITY,
        Float::NEGATIVE_INFINITY,
        Float::ZERO,
        Float::NEGATIVE_ZERO
    ]
    .into_iter()
    .chain(exhaustive_mixed_extreme_nonzero_finite_floats())
}

struct FloatWithPrecisionRangeGenerator;

impl ExhaustiveDependentPairsYsGenerator<u64, Float, Box<dyn Iterator<Item = Float>>>
    for FloatWithPrecisionRangeGenerator
{
    #[inline]
    fn get_ys(&self, &prec: &u64) -> Box<dyn Iterator<Item = Float>> {
        Box::new(exhaustive_positive_floats_with_precision(prec))
    }
}

fn exhaustive_floats_with_precision_inclusive_range(prec_lo: u64, prec_hi: u64) -> It<Float> {
    Box::new(
        exhaustive_dependent_pairs(
            bit_distributor_sequence(
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
            ),
            primitive_int_increasing_inclusive_range(prec_lo, prec_hi),
            FloatWithPrecisionRangeGenerator,
        )
        .map(|p| p.1),
    )
}

struct FloatPairWithPrecisionRangeGenerator;

impl
    ExhaustiveDependentPairsYsGenerator<
        u64,
        (Float, Float),
        Box<dyn Iterator<Item = (Float, Float)>>,
    > for FloatPairWithPrecisionRangeGenerator
{
    #[inline]
    fn get_ys(&self, &prec: &u64) -> Box<dyn Iterator<Item = (Float, Float)>> {
        Box::new(exhaustive_pairs_from_single(
            exhaustive_positive_floats_with_precision(prec),
        ))
    }
}

fn exhaustive_float_pairs_with_precision_inclusive_range(
    prec_lo: u64,
    prec_hi: u64,
) -> It<(Float, Float)> {
    Box::new(
        exhaustive_dependent_pairs(
            bit_distributor_sequence(
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
            ),
            primitive_int_increasing_inclusive_range(prec_lo, prec_hi),
            FloatPairWithPrecisionRangeGenerator,
        )
        .map(|p| p.1),
    )
}

struct FloatPairWithPrecisionRangesGenerator;

impl
    ExhaustiveDependentPairsYsGenerator<
        (u64, u64),
        (Float, Float),
        Box<dyn Iterator<Item = (Float, Float)>>,
    > for FloatPairWithPrecisionRangesGenerator
{
    #[inline]
    fn get_ys(&self, &precs: &(u64, u64)) -> Box<dyn Iterator<Item = (Float, Float)>> {
        Box::new(exhaustive_pairs(
            exhaustive_positive_floats_with_precision(precs.0),
            exhaustive_positive_floats_with_precision(precs.1),
        ))
    }
}

fn exhaustive_float_pairs_with_precisions(precisions: It<(u64, u64)>) -> It<(Float, Float)> {
    Box::new(
        exhaustive_dependent_pairs(
            bit_distributor_sequence(
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
            ),
            precisions,
            FloatPairWithPrecisionRangesGenerator,
        )
        .map(|p| p.1),
    )
}

// -- (Float, Float) --

pub fn exhaustive_float_pair_gen() -> It<(Float, Float)> {
    Box::new(exhaustive_pairs_from_single(exhaustive_floats()))
}

pub fn exhaustive_float_pair_gen_var_1() -> It<(Float, Float)> {
    Box::new(exhaustive_pairs_from_single(exhaustive_finite_floats()))
}

pub fn exhaustive_float_pair_gen_var_2() -> It<(Float, Float)> {
    exhaustive_float_pairs_with_precision_inclusive_range(1, Limb::WIDTH - 1)
}

pub fn exhaustive_float_pair_gen_var_3() -> It<(Float, Float)> {
    Box::new(exhaustive_pairs_from_single(
        exhaustive_positive_floats_with_precision(Limb::WIDTH),
    ))
}

pub fn exhaustive_float_pair_gen_var_4() -> It<(Float, Float)> {
    exhaustive_float_pairs_with_precision_inclusive_range(Limb::WIDTH + 1, (Limb::WIDTH << 1) - 1)
}

pub fn exhaustive_float_pair_gen_var_5() -> It<(Float, Float)> {
    Box::new(exhaustive_pairs_from_single(
        exhaustive_positive_floats_with_precision(Limb::WIDTH << 1),
    ))
}

pub fn exhaustive_float_pair_gen_var_6() -> It<(Float, Float)> {
    exhaustive_float_pairs_with_precision_inclusive_range(
        (Limb::WIDTH << 1) + 1,
        (Limb::WIDTH * 3) - 1,
    )
}

pub fn exhaustive_float_pair_gen_var_7() -> It<(Float, Float)> {
    exhaustive_float_pairs_with_precision_inclusive_range(Limb::WIDTH * 3, u64::MAX)
}

pub fn exhaustive_float_pair_gen_var_8() -> It<(Float, Float)> {
    exhaustive_float_pairs_with_precisions(Box::new(
        exhaustive_pairs(
            exhaustive_positive_primitive_ints(),
            primitive_int_increasing_inclusive_range(1, Limb::WIDTH),
        )
        .filter(|&(x, y)| x != y),
    ))
}

pub fn exhaustive_float_pair_gen_var_9() -> It<(Float, Float)> {
    exhaustive_float_pairs_with_precisions(Box::new(
        exhaustive_pairs(
            exhaustive_positive_primitive_ints(),
            primitive_int_increasing_inclusive_range(Limb::WIDTH + 1, u64::MAX),
        )
        .filter(|&(x, y)| x != y),
    ))
}

pub fn exhaustive_float_pair_gen_var_10() -> It<(Float, Float)> {
    Box::new(exhaustive_pairs_from_single(
        exhaustive_mixed_extreme_floats(),
    ))
}

// -- (Float, Float, Float) --

pub fn exhaustive_float_triple_gen() -> It<(Float, Float, Float)> {
    Box::new(exhaustive_triples_from_single(exhaustive_floats()))
}

// -- (Float, Float, Integer) --

pub fn exhaustive_float_float_integer_triple_gen() -> It<(Float, Float, Integer)> {
    Box::new(exhaustive_triples_xxy(
        exhaustive_floats(),
        exhaustive_integers(),
    ))
}

// -- (Float, Float, Natural) --

pub fn exhaustive_float_float_natural_triple_gen() -> It<(Float, Float, Natural)> {
    Box::new(exhaustive_triples_xxy(
        exhaustive_floats(),
        exhaustive_naturals(),
    ))
}

// -- (Float, Float, PrimitiveFloat) --

pub fn exhaustive_float_float_primitive_float_triple_gen<T: PrimitiveFloat>()
-> It<(Float, Float, T)> {
    Box::new(exhaustive_triples_xxy(
        exhaustive_floats(),
        exhaustive_primitive_floats(),
    ))
}

// -- (Float, Float, PrimitiveSigned) --

pub fn exhaustive_float_float_signed_triple_gen<T: PrimitiveSigned>() -> It<(Float, Float, T)> {
    Box::new(exhaustive_triples_xxy(
        exhaustive_floats(),
        exhaustive_signeds(),
    ))
}

// -- (Float, Float, PrimitiveUnsigned) --

pub fn exhaustive_float_float_unsigned_triple_gen<T: PrimitiveUnsigned>() -> It<(Float, Float, T)> {
    Box::new(exhaustive_triples_xxy(
        exhaustive_floats(),
        exhaustive_unsigneds(),
    ))
}

pub fn exhaustive_float_float_unsigned_triple_gen_var_1<T: PrimitiveUnsigned>()
-> It<(Float, Float, T)> {
    Box::new(exhaustive_triples_xxy_custom_output(
        exhaustive_floats(),
        exhaustive_positive_primitive_ints::<T>(),
        BitDistributorOutputType::normal(1),
        BitDistributorOutputType::normal(1),
        BitDistributorOutputType::tiny(),
    ))
}

pub fn exhaustive_float_float_unsigned_triple_gen_var_2<T: PrimitiveUnsigned>()
-> It<(Float, Float, T)> {
    Box::new(exhaustive_triples_xxy_custom_output(
        exhaustive_mixed_extreme_floats(),
        exhaustive_positive_primitive_ints::<T>(),
        BitDistributorOutputType::normal(1),
        BitDistributorOutputType::normal(1),
        BitDistributorOutputType::tiny(),
    ))
}

// -- (Float, Float, PrimitiveUnsigned, RoundingMode) --

pub(crate) fn add_prec_round_valid(
    x: &Float,
    y: &Float,
    prec: u64,
    rm: RoundingMode,
    extreme: bool,
) -> bool {
    if rm != Exact {
        true
    } else if extreme {
        x.add_prec_round_ref_ref(y, prec, Floor).1 == Equal
    } else if let (Ok(rx), Ok(ry)) = (Rational::try_from(x), Rational::try_from(y)) {
        let sum = Float::exact_from(rx + ry);
        if let Some(min_prec) = sum.get_min_prec() {
            prec >= min_prec
        } else {
            true
        }
    } else {
        true
    }
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_1()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| add_prec_round_valid(x, y, *prec, *rm, false)),
    )
}

pub(crate) fn sub_prec_round_valid(
    x: &Float,
    y: &Float,
    prec: u64,
    rm: RoundingMode,
    extreme: bool,
) -> bool {
    if rm != Exact {
        return true;
    }
    if extreme {
        x.sub_prec_round_ref_ref(y, prec, Floor).1 == Equal
    } else if let (Ok(rx), Ok(ry)) = (Rational::try_from(x), Rational::try_from(y)) {
        let diff = Float::exact_from(rx - ry);
        if let Some(min_prec) = diff.get_min_prec() {
            prec >= min_prec
        } else {
            true
        }
    } else {
        true
    }
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_2()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| sub_prec_round_valid(x, y, *prec, *rm, false)),
    )
}

pub(crate) fn mul_prec_round_valid(
    x: &Float,
    y: &Float,
    prec: u64,
    rm: RoundingMode,
    extreme: bool,
) -> bool {
    if rm != Exact {
        true
    } else if extreme {
        x.mul_prec_round_ref_ref(y, prec, Floor).1 == Equal
    } else if let (Ok(rx), Ok(ry)) = (Rational::try_from(x), Rational::try_from(y)) {
        let product = Float::exact_from(rx * ry);
        if let Some(min_prec) = product.get_min_prec() {
            prec >= min_prec
        } else {
            true
        }
    } else {
        true
    }
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_3()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| mul_prec_round_valid(x, y, *prec, *rm, false)),
    )
}

pub(crate) fn div_prec_round_valid(
    x: &Float,
    y: &Float,
    prec: u64,
    rm: RoundingMode,
    extreme: bool,
) -> bool {
    if rm != Exact || *y == 0u32 {
        true
    } else if extreme {
        x.div_prec_round_ref_ref(y, prec, Floor).1 == Equal
    } else if let (Ok(rx), Ok(ry)) = (Rational::try_from(x), Rational::try_from(y)) {
        if let Ok(quotient) = Float::try_from(rx / ry) {
            if let Some(min_prec) = quotient.get_min_prec() {
                prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        true
    }
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_4()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| div_prec_round_valid(x, y, *prec, *rm, false)),
    )
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_5()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_mixed_extreme_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| add_prec_round_valid(x, y, *prec, *rm, true)),
    )
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_6()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_mixed_extreme_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| sub_prec_round_valid(x, y, *prec, *rm, true)),
    )
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_7()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_mixed_extreme_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| mul_prec_round_valid(x, y, *prec, *rm, true)),
    )
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_8()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_mixed_extreme_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| div_prec_round_valid(x, y, *prec, *rm, true)),
    )
}

pub fn agm_prec_round_valid(x: &Float, y: &Float, prec: u64, rm: RoundingMode) -> bool {
    rm != Exact
        || !x.is_normal()
        || !y.is_normal()
        || *x < 0u32
        || *y < 0u32
        || x == y && Float::from_float_prec_round_ref(x, prec, Floor).1 == Equal
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_9()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| agm_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_10()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_mixed_extreme_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| agm_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn log_base_float_base_prec_round_valid(
    x: &Float,
    base: &Float,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if rm != Exact {
        return true;
    }
    // Special and degenerate inputs (x or base not finite-positive, or x = 1, or base = 1) yield
    // exact results (0, +-infinity, or NaN) and never panic with Exact.
    if !x.is_finite()
        || *x <= 0u32
        || *x == 1u32
        || !base.is_finite()
        || *base <= 0u32
        || *base == 1u32
    {
        return true;
    }
    // x, base finite positive and not 1: Exact only when log_base(x) is rational and representable.
    log_base_float_base_rational(x, base, prec)
        .is_some_and(|q| Float::from_rational_prec(q, prec).1 == Equal)
}

pub(crate) fn log_base_float_base_round_valid(x: &Float, base: &Float, rm: RoundingMode) -> bool {
    if rm != Exact {
        return true;
    }
    if !x.is_finite()
        || *x <= 0u32
        || *x == 1u32
        || !base.is_finite()
        || *base <= 0u32
        || *base == 1u32
    {
        return true;
    }
    log_base_float_base_rational(x, base, x.significant_bits())
        .is_some_and(|q| Float::from_rational_prec(q, x.significant_bits()).1 == Equal)
}

// All `(Float, Float, u64, RoundingMode)` that are valid inputs to
// `Float.log_base_float_base_prec_round`.
pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_11()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| log_base_float_base_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_12()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_mixed_extreme_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| log_base_float_base_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn log_base_float_base_1_plus_x_prec_round_valid(
    x: &Float,
    base: &Float,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if rm != Exact {
        return true;
    }
    // Special and degenerate inputs (x not finite, x <= -1, x = +-0, or base not finite-positive,
    // or base = 1) yield exact results (0, +-infinity, or NaN) and never panic with Exact.
    if !x.is_finite()
        || *x <= -1i32
        || *x == 0u32
        || !base.is_finite()
        || *base <= 0u32
        || *base == 1u32
    {
        return true;
    }
    log_base_float_base_1_plus_x_rational(x, base, prec)
        .is_some_and(|q| Float::from_rational_prec(q, prec).1 == Equal)
}

pub(crate) fn log_base_float_base_1_plus_x_round_valid(
    x: &Float,
    base: &Float,
    rm: RoundingMode,
) -> bool {
    if rm != Exact {
        return true;
    }
    if !x.is_finite()
        || *x <= -1i32
        || *x == 0u32
        || !base.is_finite()
        || *base <= 0u32
        || *base == 1u32
    {
        return true;
    }
    log_base_float_base_1_plus_x_rational(x, base, x.significant_bits())
        .is_some_and(|q| Float::from_rational_prec(q, x.significant_bits()).1 == Equal)
}

// All `(Float, Float, u64, RoundingMode)` that are valid inputs to
// `Float.log_base_float_base_1_plus_x_prec_round`.
pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_13()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| log_base_float_base_1_plus_x_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn exhaustive_float_float_unsigned_rounding_mode_quadruple_gen_var_14()
-> It<(Float, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_mixed_extreme_floats(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| log_base_float_base_1_plus_x_prec_round_valid(x, y, *prec, *rm)),
    )
}

// -- (Float, Float, Rational) --

pub fn exhaustive_float_float_rational_triple_gen() -> It<(Float, Float, Rational)> {
    Box::new(exhaustive_triples_xxy(
        exhaustive_floats(),
        exhaustive_rationals(),
    ))
}

// -- (Float, Float, RoundingMode) --

pub(crate) fn add_round_valid(x: &Float, y: &Float, rm: RoundingMode, extreme: bool) -> bool {
    if rm != Exact {
        true
    } else if extreme {
        x.add_round_ref_ref(y, Floor).1 == Equal
    } else if let (Some(x_prec), Some(y_prec)) = (x.get_prec(), y.get_prec()) {
        let sum = Float::exact_from(Rational::exact_from(x) + Rational::exact_from(y));
        if let Some(min_prec) = sum.get_min_prec() {
            max(x_prec, y_prec) >= min_prec
        } else {
            true
        }
    } else {
        true
    }
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_1() -> It<(Float, Float, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| add_round_valid(x, y, *rm, false)),
    )
}

pub(crate) fn sub_round_valid(x: &Float, y: &Float, rm: RoundingMode, extreme: bool) -> bool {
    if rm != Exact {
        true
    } else if extreme {
        x.sub_round_ref_ref(y, Floor).1 == Equal
    } else if let (Some(x_prec), Some(y_prec)) = (x.get_prec(), y.get_prec()) {
        let diff = Float::exact_from(Rational::exact_from(x) - Rational::exact_from(y));
        if let Some(min_prec) = diff.get_min_prec() {
            max(x_prec, y_prec) >= min_prec
        } else {
            true
        }
    } else {
        true
    }
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_2() -> It<(Float, Float, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| sub_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_3() -> It<(Float, Float, RoundingMode)> {
    Box::new(exhaustive_triples_xxy(
        exhaustive_floats(),
        exhaustive_rounding_modes().filter(|&rm| rm != Exact),
    ))
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_4() -> It<(Float, Float, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_2(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| add_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_5() -> It<(Float, Float, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_3(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| add_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_6() -> It<(Float, Float, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_4(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| add_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_7() -> It<(Float, Float, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_5(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| add_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_8() -> It<(Float, Float, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_6(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| add_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_9() -> It<(Float, Float, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_7(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| add_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_10() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_2(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| sub_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_11() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_3(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| sub_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_12() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_4(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| sub_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_13() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_5(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| sub_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_14() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_6(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| sub_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_15() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_7(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| sub_round_valid(x, y, *rm, false)),
    )
}

pub(crate) fn mul_round_valid(x: &Float, y: &Float, rm: RoundingMode, extreme: bool) -> bool {
    if rm != Exact {
        true
    } else if extreme {
        x.mul_round_ref_ref(y, Floor).1 == Equal
    } else if let (Some(x_prec), Some(y_prec)) = (x.get_prec(), y.get_prec()) {
        let product = Float::exact_from(Rational::exact_from(x) * Rational::exact_from(y));
        if let Some(min_prec) = product.get_min_prec() {
            max(x_prec, y_prec) >= min_prec
        } else {
            true
        }
    } else {
        true
    }
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_16() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_2(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| mul_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_17() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_2(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| mul_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_18() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_3(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| mul_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_19() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_4(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| mul_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_20() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_5(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| mul_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_21() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_6(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| mul_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_22() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_7(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| mul_round_valid(x, y, *rm, false)),
    )
}

pub(crate) fn div_round_valid(x: &Float, y: &Float, rm: RoundingMode, extreme: bool) -> bool {
    if rm != Exact || *y == 0u32 {
        true
    } else if extreme {
        x.div_round_ref_ref(y, Floor).1 == Equal
    } else if let (Some(x_prec), Some(y_prec)) = (x.get_prec(), y.get_prec()) {
        if let Ok(quotient) = Float::try_from(Rational::exact_from(x) / Rational::exact_from(y)) {
            if let Some(min_prec) = quotient.get_min_prec() {
                max(x_prec, y_prec) >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        true
    }
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_23() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_2(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| div_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_24() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_2(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| div_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_25() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_3(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| div_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_26() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_4(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| div_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_27() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_8(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| div_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_28() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_float_pair_gen_var_9(),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| div_round_valid(x, y, *rm, false)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_29() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_mixed_extreme_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| add_round_valid(x, y, *rm, true)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_30() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_mixed_extreme_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| sub_round_valid(x, y, *rm, true)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_31() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_mixed_extreme_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| mul_round_valid(x, y, *rm, true)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_32() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_mixed_extreme_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| div_round_valid(x, y, *rm, true)),
    )
}

pub(crate) fn agm_round_valid(x: &Float, y: &Float, rm: RoundingMode) -> bool {
    rm != Exact || !x.is_normal() || !y.is_normal() || *x < 0u32 || *y < 0u32 || x == y
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_33() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| agm_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_34() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_mixed_extreme_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| agm_round_valid(x, y, *rm)),
    )
}

// All `(Float, Float, RoundingMode)` that are valid inputs to `Float.log_base_float_base_round`.
pub fn exhaustive_float_float_rounding_mode_triple_gen_var_35() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| log_base_float_base_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_36() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_mixed_extreme_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| log_base_float_base_round_valid(x, y, *rm)),
    )
}

// All `(Float, Float, RoundingMode)` that are valid inputs to
// `Float.log_base_float_base_1_plus_x_round`.
pub fn exhaustive_float_float_rounding_mode_triple_gen_var_37() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| log_base_float_base_1_plus_x_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_float_rounding_mode_triple_gen_var_38() -> It<(Float, Float, RoundingMode)>
{
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs_from_single(exhaustive_mixed_extreme_floats()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| log_base_float_base_1_plus_x_round_valid(x, y, *rm)),
    )
}

// -- (Float, Integer) --

pub fn exhaustive_float_integer_pair_gen() -> It<(Float, Integer)> {
    Box::new(exhaustive_pairs(exhaustive_floats(), exhaustive_integers()))
}

pub fn exhaustive_float_integer_pair_gen_var_1() -> It<(Float, Integer)> {
    Box::new(exhaustive_pairs(
        exhaustive_finite_floats(),
        exhaustive_integers(),
    ))
}

pub fn exhaustive_float_integer_pair_gen_var_2() -> It<(Float, Integer)> {
    Box::new(exhaustive_pairs(
        exhaustive_extreme_floats(),
        exhaustive_integers(),
    ))
}

// -- (Float, Integer, Integer) --

pub fn exhaustive_float_integer_integer_triple_gen() -> It<(Float, Integer, Integer)> {
    Box::new(exhaustive_triples_xyy(
        exhaustive_floats(),
        exhaustive_integers(),
    ))
}

// -- (Float, Natural) --

pub fn exhaustive_float_natural_pair_gen() -> It<(Float, Natural)> {
    Box::new(exhaustive_pairs(exhaustive_floats(), exhaustive_naturals()))
}

pub fn exhaustive_float_natural_pair_gen_var_1() -> It<(Float, Natural)> {
    Box::new(exhaustive_pairs(
        exhaustive_finite_floats(),
        exhaustive_naturals(),
    ))
}

pub fn exhaustive_float_natural_pair_gen_var_2() -> It<(Float, Natural)> {
    Box::new(exhaustive_pairs(
        exhaustive_extreme_floats(),
        exhaustive_naturals(),
    ))
}

// -- (Float, Natural, Natural) --

pub fn exhaustive_float_natural_natural_triple_gen() -> It<(Float, Natural, Natural)> {
    Box::new(exhaustive_triples_xyy(
        exhaustive_floats(),
        exhaustive_naturals(),
    ))
}

// -- (Float, Ordering) --

pub fn exhaustive_float_ordering_pair_gen() -> It<(Float, Ordering)> {
    Box::new(exhaustive_pairs(
        exhaustive_floats(),
        exhaustive_orderings(),
    ))
}

pub fn exhaustive_float_ordering_pair_gen_var_1() -> It<(Float, Ordering)> {
    Box::new(exhaustive_pairs(
        exhaustive_extreme_floats(),
        exhaustive_orderings(),
    ))
}

// -- (Float, PrimitiveFloat) --

pub fn exhaustive_float_primitive_float_pair_gen<T: PrimitiveFloat>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs(
        exhaustive_floats(),
        exhaustive_primitive_floats(),
    ))
}

pub fn exhaustive_float_primitive_float_pair_gen_var_1<T: PrimitiveFloat>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs(
        exhaustive_extreme_floats(),
        exhaustive_primitive_floats(),
    ))
}

// -- (Float, PrimitiveFloat, PrimitiveFloat) --

pub fn exhaustive_float_primitive_float_primitive_float_triple_gen<T: PrimitiveFloat>()
-> It<(Float, T, T)> {
    Box::new(exhaustive_triples_xyy(
        exhaustive_floats(),
        exhaustive_primitive_floats(),
    ))
}

// -- (Float, PrimitiveSigned) --

pub fn exhaustive_float_signed_pair_gen<T: PrimitiveSigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs(exhaustive_floats(), exhaustive_signeds()))
}

pub fn exhaustive_float_signed_pair_gen_var_1<T: PrimitiveSigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs_big_tiny(
        exhaustive_positive_floats_with_sci_exponent(0),
        exhaustive_signeds(),
    ))
}

pub fn exhaustive_float_signed_pair_gen_var_2<T: PrimitiveSigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs_big_tiny(
        exhaustive_floats(),
        exhaustive_signeds(),
    ))
}

pub fn exhaustive_float_signed_pair_gen_var_3<T: PrimitiveSigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs_big_tiny(
        exhaustive_extreme_floats(),
        exhaustive_signeds(),
    ))
}

pub fn exhaustive_float_signed_pair_gen_var_4<T: PrimitiveSigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs(
        exhaustive_extreme_floats(),
        exhaustive_signeds(),
    ))
}

// -- (Float, PrimitiveSigned, PrimitiveSigned) --

pub fn exhaustive_float_signed_signed_triple_gen<T: PrimitiveSigned>() -> It<(Float, T, T)> {
    Box::new(exhaustive_triples_xyy(
        exhaustive_floats(),
        exhaustive_signeds(),
    ))
}

// -- (Float, PrimitiveSigned, PrimitiveUnsigned) --

pub fn exhaustive_float_signed_unsigned_triple_gen_var_1<
    T: PrimitiveSigned,
    U: PrimitiveUnsigned,
>() -> It<(Float, T, U)> {
    Box::new(exhaustive_triples(
        exhaustive_floats(),
        exhaustive_signeds(),
        exhaustive_positive_primitive_ints(),
    ))
}

pub fn exhaustive_float_signed_unsigned_triple_gen_var_2<
    T: PrimitiveSigned,
    U: PrimitiveUnsigned,
>() -> It<(Float, T, U)> {
    Box::new(exhaustive_triples(
        exhaustive_extreme_floats(),
        exhaustive_signeds(),
        exhaustive_positive_primitive_ints(),
    ))
}

// -- (Float, PrimitiveSigned, PrimitiveUnsigned, RoundingMode) --

pub fn exhaustive_float_signed_unsigned_rounding_mode_quadruple_gen_var_1<T: PrimitiveSigned>()
-> It<(Float, T, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_floats(),
                exhaustive_signeds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits, prec), rm)| shl_prec_round_valid(x, bits, prec, rm)),
    ))
}

pub fn exhaustive_float_signed_unsigned_rounding_mode_quadruple_gen_var_2<T: PrimitiveSigned>()
-> It<(Float, T, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_extreme_floats(),
                exhaustive_signeds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits, prec), rm)| shl_prec_round_valid(x, bits, prec, rm)),
    ))
}

pub fn exhaustive_float_signed_unsigned_rounding_mode_quadruple_gen_var_3<T: PrimitiveSigned>()
-> It<(Float, T, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_floats(),
                exhaustive_signeds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits, prec), rm)| shr_prec_round_valid(x, bits, prec, rm)),
    ))
}

pub fn exhaustive_float_signed_unsigned_rounding_mode_quadruple_gen_var_4<T: PrimitiveSigned>()
-> It<(Float, T, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_extreme_floats(),
                exhaustive_signeds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits, prec), rm)| shr_prec_round_valid(x, bits, prec, rm)),
    ))
}

// -- (Float, PrimitiveSigned, RoundingMode) --

pub fn exhaustive_float_signed_rounding_mode_triple_gen_var_1<T: PrimitiveSigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_signeds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits), rm)| shl_round_valid(x, bits, rm)),
    ))
}

pub fn exhaustive_float_signed_rounding_mode_triple_gen_var_2<T: PrimitiveSigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_extreme_floats(), exhaustive_signeds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits), rm)| shl_round_valid(x, bits, rm)),
    ))
}

pub fn exhaustive_float_signed_rounding_mode_triple_gen_var_3<T: PrimitiveSigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_signeds()),
            exhaustive_rounding_modes().filter(|&rm| rm != Exact),
        )
        .filter(|&((ref x, bits), rm)| shl_round_valid(x, bits, rm)),
    ))
}

pub fn exhaustive_float_signed_rounding_mode_triple_gen_var_4<T: PrimitiveSigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_signeds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits), rm)| shr_round_valid(x, bits, rm)),
    ))
}

pub fn exhaustive_float_signed_rounding_mode_triple_gen_var_5<T: PrimitiveSigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_extreme_floats(), exhaustive_signeds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits), rm)| shr_round_valid(x, bits, rm)),
    ))
}

pub fn exhaustive_float_signed_rounding_mode_triple_gen_var_6<T: PrimitiveSigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_signeds()),
            exhaustive_rounding_modes().filter(|&rm| rm != Exact),
        )
        .filter(|&((ref x, bits), rm)| shr_round_valid(x, bits, rm)),
    ))
}

// -- (Float, PrimitiveUnsigned) --

pub fn exhaustive_float_unsigned_pair_gen<T: PrimitiveUnsigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs(
        exhaustive_floats(),
        exhaustive_unsigneds(),
    ))
}

pub fn exhaustive_float_unsigned_pair_gen_var_1<T: PrimitiveUnsigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs_big_tiny(
        exhaustive_floats(),
        exhaustive_positive_primitive_ints(),
    ))
}

pub fn exhaustive_float_unsigned_pair_gen_var_2<T: PrimitiveUnsigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs_big_tiny(
        exhaustive_floats(),
        exhaustive_unsigneds(),
    ))
}

pub fn exhaustive_float_unsigned_pair_gen_var_3<T: PrimitiveUnsigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs_big_tiny(
        exhaustive_extreme_floats(),
        exhaustive_unsigneds(),
    ))
}

pub fn exhaustive_float_unsigned_pair_gen_var_4<T: PrimitiveUnsigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs_big_tiny(
        exhaustive_extreme_floats(),
        exhaustive_positive_primitive_ints(),
    ))
}

pub fn exhaustive_float_unsigned_pair_gen_var_5<T: PrimitiveUnsigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs(
        exhaustive_extreme_floats(),
        exhaustive_unsigneds(),
    ))
}

pub fn exhaustive_float_unsigned_pair_gen_var_6<T: PrimitiveUnsigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs_big_tiny(
        exhaustive_floats().filter(|x| *x > 0u32),
        exhaustive_positive_primitive_ints(),
    ))
}

pub fn exhaustive_float_unsigned_pair_gen_var_7<T: PrimitiveUnsigned>() -> It<(Float, T)> {
    Box::new(exhaustive_pairs_big_tiny(
        exhaustive_finite_floats(),
        exhaustive_positive_primitive_ints(),
    ))
}

// -- (Float, PrimitiveUnsigned, PrimitiveUnsigned) --

pub fn exhaustive_float_unsigned_unsigned_triple_gen<T: PrimitiveUnsigned>() -> It<(Float, T, T)> {
    Box::new(exhaustive_triples_xyy(
        exhaustive_floats(),
        exhaustive_unsigneds(),
    ))
}

pub fn exhaustive_float_unsigned_unsigned_triple_gen_var_1<
    T: PrimitiveUnsigned,
    U: PrimitiveUnsigned,
>() -> It<(Float, T, U)> {
    Box::new(exhaustive_triples(
        exhaustive_floats(),
        exhaustive_unsigneds(),
        exhaustive_positive_primitive_ints(),
    ))
}

pub fn exhaustive_float_unsigned_unsigned_triple_gen_var_2<
    T: PrimitiveUnsigned,
    U: PrimitiveUnsigned,
>() -> It<(Float, T, U)> {
    Box::new(exhaustive_triples(
        exhaustive_extreme_floats(),
        exhaustive_unsigneds(),
        exhaustive_positive_primitive_ints(),
    ))
}

// -- (Float, PrimitiveUnsigned, PrimitiveUnsigned, RoundingMode) --

pub fn exhaustive_float_unsigned_unsigned_rounding_mode_quadruple_gen_var_1<
    T: PrimitiveUnsigned,
>() -> It<(Float, T, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_floats(),
                exhaustive_unsigneds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits, prec), rm)| shl_prec_round_valid(x, bits, prec, rm)),
    ))
}

pub fn exhaustive_float_unsigned_unsigned_rounding_mode_quadruple_gen_var_2<
    T: PrimitiveUnsigned,
>() -> It<(Float, T, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_extreme_floats(),
                exhaustive_unsigneds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits, prec), rm)| shl_prec_round_valid(x, bits, prec, rm)),
    ))
}

pub fn exhaustive_float_unsigned_unsigned_rounding_mode_quadruple_gen_var_3<
    T: PrimitiveUnsigned,
>() -> It<(Float, T, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_floats(),
                exhaustive_unsigneds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits, prec), rm)| shr_prec_round_valid(x, bits, prec, rm)),
    ))
}

pub fn exhaustive_float_unsigned_unsigned_rounding_mode_quadruple_gen_var_4<
    T: PrimitiveUnsigned,
>() -> It<(Float, T, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_extreme_floats(),
                exhaustive_unsigneds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits, prec), rm)| shr_prec_round_valid(x, bits, prec, rm)),
    ))
}

// -- (Float, PrimitiveUnsigned, RoundingMode) --

pub fn set_prec_round_valid(x: &Float, p: u64, rm: RoundingMode) -> bool {
    rm != Exact || !x.is_finite() || x.is_zero() || x.get_prec().unwrap() <= p || {
        let significand = x.significand_ref().unwrap();
        significand_bits(significand) - significand.trailing_zeros().unwrap() <= p
    }
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_1() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| set_prec_round_valid(x, p, rm)),
    ))
}

pub fn square_prec_round_valid(x: &Float, prec: u64, rm: RoundingMode, extreme: bool) -> bool {
    if rm != Exact {
        true
    } else if extreme {
        x.square_prec_round_ref(prec, Floor).1 == Equal
    } else if let Ok(rx) = Rational::try_from(x) {
        let square = Float::exact_from(rx.square());
        if let Some(min_prec) = square.get_min_prec() {
            prec >= min_prec
        } else {
            true
        }
    } else {
        true
    }
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_2() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| square_prec_round_valid(x, p, rm, false)),
    ))
}

pub fn reciprocal_prec_round_valid(x: &Float, prec: u64, rm: RoundingMode, extreme: bool) -> bool {
    if rm != Exact || *x == 0 {
        true
    } else if extreme {
        x.reciprocal_prec_round_ref(prec, Floor).1 == Equal
    } else if let Ok(rx) = Rational::try_from(x) {
        if let Ok(reciprocal) = Float::try_from(rx.reciprocal()) {
            if let Some(min_prec) = reciprocal.get_min_prec() {
                prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        true
    }
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_3() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| reciprocal_prec_round_valid(x, p, rm, false)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_4() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| set_prec_round_valid(x, p, rm)),
    ))
}

pub fn shl_round_valid<T: PrimitiveInt>(x: &Float, bits: T, rm: RoundingMode) -> bool {
    rm != Exact || !x.is_finite() || x.is_zero() || {
        let exponent = x.get_exponent().unwrap();
        if let Ok(bits) = bits.try_into()
            && let Some(new_exponent) = exponent.checked_add(bits)
        {
            return (Float::MIN_EXPONENT..=Float::MAX_EXPONENT).contains(&new_exponent);
        }
        false
    }
}

pub fn shl_prec_round_valid<T: PrimitiveInt>(
    x: &Float,
    bits: T,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    rm != Exact || !x.is_normal() || x.shl_prec_round_ref(bits, prec, Floor).1 == Equal
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_5<T: PrimitiveUnsigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_unsigneds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits), rm)| shl_round_valid(x, bits, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_6<T: PrimitiveUnsigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_extreme_floats(), exhaustive_unsigneds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits), rm)| shl_round_valid(x, bits, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_7<T: PrimitiveUnsigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_unsigneds()),
            exhaustive_rounding_modes().filter(|&rm| rm != Exact),
        )
        .filter(|&((ref x, bits), rm)| shl_round_valid(x, bits, rm)),
    ))
}

pub fn shr_round_valid<T: PrimitiveInt>(x: &Float, bits: T, rm: RoundingMode) -> bool {
    rm != Exact || !x.is_finite() || x.is_zero() || {
        let exponent = x.get_exponent().unwrap();
        if let Ok(bits) = bits.try_into()
            && let Some(new_exponent) = exponent.checked_sub(bits)
        {
            return (Float::MIN_EXPONENT..=Float::MAX_EXPONENT).contains(&new_exponent);
        }
        false
    }
}

pub fn shr_prec_round_valid<T: PrimitiveInt>(
    x: &Float,
    bits: T,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    rm != Exact || !x.is_normal() || x.shr_prec_round_ref(bits, prec, Floor).1 == Equal
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_8<T: PrimitiveUnsigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_unsigneds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits), rm)| shr_round_valid(x, bits, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_9<T: PrimitiveUnsigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_extreme_floats(), exhaustive_unsigneds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, bits), rm)| shr_round_valid(x, bits, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_10<T: PrimitiveUnsigned>()
-> It<(Float, T, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_unsigneds()),
            exhaustive_rounding_modes().filter(|&rm| rm != Exact),
        )
        .filter(|&((ref x, bits), rm)| shr_round_valid(x, bits, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_11() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| square_prec_round_valid(x, p, rm, true)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_12() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| reciprocal_prec_round_valid(x, p, rm, true)),
    ))
}

pub fn sqrt_prec_round_valid(x: &Float, prec: u64, rm: RoundingMode) -> bool {
    rm != Exact || x.sqrt_prec_round_ref(prec, Floor).1 == Equal
}

pub fn reciprocal_sqrt_prec_round_valid(x: &Float, prec: u64, rm: RoundingMode) -> bool {
    rm != Exact || x.reciprocal_sqrt_prec_round_ref(prec, Floor).1 == Equal
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_13() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| sqrt_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_14() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| sqrt_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_15() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| reciprocal_sqrt_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_16() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| reciprocal_sqrt_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_17() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(lex_pairs(
        exhaustive_pairs_big_tiny(
            exhaustive_floats().filter(|x| *x > 0u32),
            exhaustive_positive_primitive_ints(),
        ),
        exhaustive_rounding_modes(),
    )))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_18() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(lex_pairs(
        exhaustive_pairs_big_tiny(
            exhaustive_finite_floats(),
            exhaustive_positive_primitive_ints(),
        ),
        exhaustive_rounding_modes(),
    )))
}

pub fn ln_prec_round_valid(x: &Float, _prec: u64, rm: RoundingMode) -> bool {
    rm != Exact || *x <= 0u32 || *x == 1u32
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_19() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| ln_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_20() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| ln_prec_round_valid(x, p, rm)),
    ))
}

pub fn ln_1_plus_x_prec_round_valid(x: &Float, _prec: u64, rm: RoundingMode) -> bool {
    rm != Exact || *x == 0u32 || *x <= -1i32
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_21() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| ln_1_plus_x_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_22() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| ln_1_plus_x_prec_round_valid(x, p, rm)),
    ))
}

pub fn log_base_2_prec_round_valid(x: &Float, prec: u64, rm: RoundingMode) -> bool {
    rm != Exact
        || *x <= 0u32
        || x.is_power_of_2()
            && Float::from_signed_prec(i64::from(x.get_exponent().unwrap()) - 1, prec).1 == Equal
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_23() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| log_base_2_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_24() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| log_base_2_prec_round_valid(x, p, rm)),
    ))
}

pub fn log_base_power_of_2_prec_round_valid(
    x: &Float,
    pow: i64,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if pow == 0 {
        return false;
    }
    rm != Exact
        || !x.is_finite()
        || *x <= 0u32
        || *x == 1u32
        || x.is_power_of_2()
            && Float::from(i64::from(x.get_exponent().unwrap()) - 1)
                .div_prec(Float::from(pow), prec)
                .1
                == Equal
}

pub fn log_base_prec_round_valid(x: &Float, base: u64, prec: u64, rm: RoundingMode) -> bool {
    if base < 2 {
        return false;
    }
    if rm != Exact || !x.is_finite() || *x <= 0u32 || *x == 1u32 {
        return true;
    }
    // rm == Exact and x is finite, positive, and not 1: exact only when log_base(x) is a rational
    // that is representable at the target precision.
    if base.is_power_of_2() {
        return log_base_power_of_2_prec_round_valid(x, i64::from(base.trailing_zeros()), prec, rm);
    }
    match rational_log_base(x, base) {
        Some(q) => Float::from_rational_prec_round(q, prec, Nearest).1 == Equal,
        None => false,
    }
}

pub fn exhaustive_float_unsigned_unsigned_rounding_mode_quadruple_gen_var_5()
-> It<(Float, u64, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_floats(),
                primitive_int_increasing_inclusive_range(2, u64::MAX),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, base, prec), rm)| log_base_prec_round_valid(x, base, prec, rm)),
    ))
}

pub fn exhaustive_float_unsigned_unsigned_rounding_mode_quadruple_gen_var_6()
-> It<(Float, u64, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_extreme_floats(),
                primitive_int_increasing_inclusive_range(2, u64::MAX),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, base, prec), rm)| log_base_prec_round_valid(x, base, prec, rm)),
    ))
}

pub fn log_base_1_plus_x_prec_round_valid(
    x: &Float,
    base: u64,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if base < 2 {
        return false;
    }
    if rm != Exact || !x.is_finite() || *x == 0u32 || *x <= -1i32 {
        return true;
    }
    if base.is_power_of_2() {
        return log_base_power_of_2_1_plus_x_prec_round_valid(
            x,
            i64::from(base.trailing_zeros()),
            prec,
            rm,
        );
    }
    // rm == Exact and x is finite, nonzero, and > -1: exact only when 1 + x = g^m and m / e_base is
    // representable at the target precision.
    log_base_1_plus_x_rational(x, base)
        .is_some_and(|q| Float::from_rational_prec(q, prec).1 == Equal)
}

pub fn exhaustive_float_unsigned_unsigned_rounding_mode_quadruple_gen_var_7()
-> It<(Float, u64, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_floats(),
                primitive_int_increasing_inclusive_range(2, u64::MAX),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, base, prec), rm)| log_base_1_plus_x_prec_round_valid(x, base, prec, rm)),
    ))
}

pub fn exhaustive_float_unsigned_unsigned_rounding_mode_quadruple_gen_var_8()
-> It<(Float, u64, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_extreme_floats(),
                primitive_int_increasing_inclusive_range(2, u64::MAX),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, base, prec), rm)| log_base_1_plus_x_prec_round_valid(x, base, prec, rm)),
    ))
}

pub fn exhaustive_float_signed_unsigned_rounding_mode_quadruple_gen_var_5()
-> It<(Float, i64, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_floats(),
                exhaustive_nonzero_signeds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, pow, prec), rm)| log_base_power_of_2_prec_round_valid(x, pow, prec, rm)),
    ))
}

pub fn exhaustive_float_signed_unsigned_rounding_mode_quadruple_gen_var_6()
-> It<(Float, i64, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_extreme_floats(),
                exhaustive_nonzero_signeds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, pow, prec), rm)| log_base_power_of_2_prec_round_valid(x, pow, prec, rm)),
    ))
}

pub fn log_base_2_1_plus_x_prec_round_valid(x: &Float, _prec: u64, rm: RoundingMode) -> bool {
    rm != Exact || *x == 0u32 || *x <= -1i32
}

pub fn log_base_power_of_2_1_plus_x_prec_round_valid(
    x: &Float,
    pow: i64,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if pow == 0 {
        return false;
    }
    // For `Exact` the result must be representable: this happens when `x` is special (NaN,
    // infinite, zero, or at most -1, all of which give NaN, an infinity, or a signed zero), or when
    // `1 + x = 2^m` and `m / pow` rounds exactly at `prec`.
    rm != Exact
        || !x.is_finite()
        || *x == 0u32
        || *x <= -1i32
        || crate::arithmetic::log_base_2_1_plus_x::log_base_2_1_plus_x_exact(x)
            .is_some_and(|m| Float::from(m).div_prec(Float::from(pow), prec).1 == Equal)
}

pub fn exhaustive_float_signed_unsigned_rounding_mode_quadruple_gen_var_7()
-> It<(Float, i64, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_floats(),
                exhaustive_nonzero_signeds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, pow, prec), rm)| {
            log_base_power_of_2_1_plus_x_prec_round_valid(x, pow, prec, rm)
        }),
    ))
}

pub fn exhaustive_float_signed_unsigned_rounding_mode_quadruple_gen_var_8()
-> It<(Float, i64, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples(
                exhaustive_extreme_floats(),
                exhaustive_nonzero_signeds(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, pow, prec), rm)| {
            log_base_power_of_2_1_plus_x_prec_round_valid(x, pow, prec, rm)
        }),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_25() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| log_base_2_1_plus_x_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_26() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| log_base_2_1_plus_x_prec_round_valid(x, p, rm)),
    ))
}

// -- (Float, Rational) --

pub fn exhaustive_float_rational_pair_gen() -> It<(Float, Rational)> {
    Box::new(exhaustive_pairs(
        exhaustive_floats(),
        exhaustive_rationals(),
    ))
}

pub fn exhaustive_float_rational_pair_gen_var_1() -> It<(Float, Rational)> {
    Box::new(exhaustive_pairs(
        exhaustive_finite_floats(),
        exhaustive_rationals(),
    ))
}

pub fn exhaustive_float_rational_pair_gen_var_2() -> It<(Float, Rational)> {
    Box::new(exhaustive_pairs(
        exhaustive_extreme_floats(),
        exhaustive_rationals(),
    ))
}

// -- (Float, Rational, PrimitiveUnsigned) --

pub fn exhaustive_float_rational_unsigned_triple_gen_var_1<T: PrimitiveUnsigned>()
-> It<(Float, Rational, T)> {
    Box::new(exhaustive_triples_custom_output(
        exhaustive_floats(),
        exhaustive_rationals(),
        exhaustive_positive_primitive_ints::<T>(),
        BitDistributorOutputType::normal(1),
        BitDistributorOutputType::normal(1),
        BitDistributorOutputType::tiny(),
    ))
}

pub fn exhaustive_float_rational_unsigned_triple_gen_var_2<T: PrimitiveUnsigned>()
-> It<(Float, Rational, T)> {
    Box::new(exhaustive_triples_custom_output(
        exhaustive_extreme_floats(),
        exhaustive_rationals(),
        exhaustive_positive_primitive_ints::<T>(),
        BitDistributorOutputType::normal(1),
        BitDistributorOutputType::normal(1),
        BitDistributorOutputType::tiny(),
    ))
}

// -- (Float, Rational, PrimitiveUnsigned, RoundingMode) --

pub(crate) fn add_rational_prec_round_valid(
    x: &Float,
    y: &Rational,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if rm != Exact {
        return true;
    }
    if let Ok(rx) = Rational::try_from(x) {
        if let Ok(sum) = Float::try_from(rx + y) {
            if let Some(min_prec) = sum.get_min_prec() {
                prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        true
    }
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_1()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| add_rational_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub(crate) fn sub_rational_prec_round_valid(
    x: &Float,
    y: &Rational,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if rm != Exact {
        return true;
    }
    if let Ok(rx) = Rational::try_from(x) {
        if let Ok(diff) = Float::try_from(rx - y) {
            if let Some(min_prec) = diff.get_min_prec() {
                prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        true
    }
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_2()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| sub_rational_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub(crate) fn mul_rational_prec_round_valid(
    x: &Float,
    y: &Rational,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if rm != Exact {
        return true;
    }
    if let Ok(rx) = Rational::try_from(x) {
        if let Ok(product) = Float::try_from(rx * y) {
            if let Some(min_prec) = product.get_min_prec() {
                prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        true
    }
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_3()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| mul_rational_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub(crate) fn div_rational_prec_round_valid(
    x: &Float,
    y: &Rational,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if rm != Exact || *y == 0u32 {
        return true;
    }
    if let Ok(rx) = Rational::try_from(x) {
        if let Ok(quotient) = Float::try_from(rx / y) {
            if let Some(min_prec) = quotient.get_min_prec() {
                prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        true
    }
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_4()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| div_rational_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub(crate) fn rational_div_float_prec_round_valid(
    x: &Float,
    y: &Rational,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if rm != Exact || *x == 0u32 {
        return true;
    }
    if let Ok(rx) = Rational::try_from(x) {
        if let Ok(quotient) = Float::try_from(y / rx) {
            if let Some(min_prec) = quotient.get_min_prec() {
                prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        true
    }
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_5()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| rational_div_float_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_6()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_extreme_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| add_rational_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_7()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_extreme_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| sub_rational_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_8()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_extreme_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| mul_rational_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_9()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_extreme_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| div_rational_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_10()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_extreme_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| rational_div_float_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn log_base_rational_base_prec_round_valid(
    x: &Float,
    base: &Rational,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if *base <= 1u32 {
        // The base must be greater than 1.
        return false;
    }
    if rm != Exact || !x.is_finite() || *x <= 0u32 || *x == 1u32 {
        return true;
    }
    // rm == Exact and x is finite, positive, and not 1: exact only when log_base(x) is rational and
    // representable at the target precision.
    rational_log_base_rational_base(x, base, prec)
        .is_some_and(|q| Float::from_rational_prec(q, prec).1 == Equal)
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_11()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| log_base_rational_base_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_12()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_extreme_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| log_base_rational_base_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn log_base_rational_base_1_plus_x_prec_round_valid(
    x: &Float,
    base: &Rational,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if *base <= 1u32 {
        // The base must be greater than 1.
        return false;
    }
    if rm != Exact || !x.is_finite() || *x == 0u32 || *x <= -1i32 {
        return true;
    }
    // rm == Exact and x is finite, nonzero, and > -1: exact only when 1 + x = g^m and m / e_base is
    // representable at the target precision.
    rational_log_base_rational_base_1_plus_x(x, base)
        .is_some_and(|q| Float::from_rational_prec(q, prec).1 == Equal)
}

pub(crate) fn log_base_rational_base_1_plus_x_round_valid(
    x: &Float,
    base: &Rational,
    rm: RoundingMode,
) -> bool {
    if *base <= 1u32 {
        return false;
    }
    if rm != Exact || !x.is_finite() || *x == 0u32 || *x <= -1i32 {
        return true;
    }
    rational_log_base_rational_base_1_plus_x(x, base)
        .is_some_and(|q| Float::from_rational_prec(q, x.significant_bits()).1 == Equal)
}

// All `(Float, Rational, u64, RoundingMode)` that are valid inputs to
// `Float.log_base_rational_base_1_plus_x_prec_round`.
pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_13()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| {
            log_base_rational_base_1_plus_x_prec_round_valid(x, y, *prec, *rm)
        }),
    )
}

pub fn exhaustive_float_rational_unsigned_rounding_mode_quadruple_gen_var_14()
-> It<(Float, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_extreme_floats(),
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| {
            log_base_rational_base_1_plus_x_prec_round_valid(x, y, *prec, *rm)
        }),
    )
}

// -- (Float, Rational, Rational) --

pub fn exhaustive_float_rational_rational_triple_gen() -> It<(Float, Rational, Rational)> {
    Box::new(exhaustive_triples_xyy(
        exhaustive_floats(),
        exhaustive_rationals(),
    ))
}

// -- (Float, Rational, RoundingMode) --

pub(crate) fn add_rational_round_valid(x: &Float, y: &Rational, rm: RoundingMode) -> bool {
    if rm != Exact {
        true
    } else if let Some(x_prec) = x.get_prec() {
        if let Ok(sum) = Float::try_from(Rational::exact_from(x) + y) {
            if let Some(min_prec) = sum.get_min_prec() {
                x_prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        // y must be representable by precision-1 float
        y.is_power_of_2()
    }
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_1()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| add_rational_round_valid(x, y, *rm)),
    )
}

pub(crate) fn sub_rational_round_valid(x: &Float, y: &Rational, rm: RoundingMode) -> bool {
    if rm != Exact {
        true
    } else if let Some(x_prec) = x.get_prec() {
        if let Ok(diff) = Float::try_from(Rational::exact_from(x) - y) {
            if let Some(min_prec) = diff.get_min_prec() {
                x_prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        // y must be representable by precision-1 float
        y.is_power_of_2()
    }
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_2()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| sub_rational_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_3()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(exhaustive_triples(
        exhaustive_floats(),
        exhaustive_rationals(),
        exhaustive_rounding_modes().filter(|&rm| rm != Exact),
    ))
}

pub(crate) fn mul_rational_round_valid(x: &Float, y: &Rational, rm: RoundingMode) -> bool {
    if rm != Exact {
        true
    } else if let Some(x_prec) = x.get_prec() {
        if let Ok(product) = Float::try_from(Rational::exact_from(x) * y) {
            if let Some(min_prec) = product.get_min_prec() {
                x_prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        // y must be representable by precision-1 float
        y.is_power_of_2()
    }
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_4()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| mul_rational_round_valid(x, y, *rm)),
    )
}

pub(crate) fn div_rational_round_valid(x: &Float, y: &Rational, rm: RoundingMode) -> bool {
    if rm != Exact || *y == 0 {
        true
    } else if let Some(x_prec) = x.get_prec() {
        if let Ok(quotient) = Float::try_from(Rational::exact_from(x) / y) {
            if let Some(min_prec) = quotient.get_min_prec() {
                x_prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        // y must be representable by precision-1 float
        y.is_power_of_2()
    }
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_5()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| div_rational_round_valid(x, y, *rm)),
    )
}

pub(crate) fn rational_div_float_round_valid(x: &Float, y: &Rational, rm: RoundingMode) -> bool {
    if rm != Exact || *x == 0u32 {
        true
    } else if let Some(prec) = x.get_prec() {
        if let Ok(quotient) = Float::try_from(y / Rational::exact_from(x)) {
            if let Some(min_prec) = quotient.get_min_prec() {
                prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        true
    }
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_6()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| rational_div_float_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_7()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_extreme_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| add_rational_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_8()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_extreme_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| sub_rational_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_9()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_extreme_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| mul_rational_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_10()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_extreme_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| div_rational_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_11()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_extreme_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| rational_div_float_round_valid(x, y, *rm)),
    )
}

pub(crate) fn log_base_rational_base_round_valid(
    x: &Float,
    base: &Rational,
    rm: RoundingMode,
) -> bool {
    if *base <= 1u32 {
        return false;
    }
    if rm != Exact || !x.is_finite() || *x <= 0u32 || *x == 1u32 {
        return true;
    }
    rational_log_base_rational_base(x, base, x.significant_bits())
        .is_some_and(|q| Float::from_rational_prec(q, x.significant_bits()).1 == Equal)
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_12()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| log_base_rational_base_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_13()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_extreme_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| log_base_rational_base_round_valid(x, y, *rm)),
    )
}

// All `(Float, Rational, RoundingMode)` that are valid inputs to
// `Float.log_base_rational_base_1_plus_x_round`.
pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_14()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| log_base_rational_base_1_plus_x_round_valid(x, y, *rm)),
    )
}

pub fn exhaustive_float_rational_rounding_mode_triple_gen_var_15()
-> It<(Float, Rational, RoundingMode)> {
    Box::new(
        reshape_2_1_to_3(Box::new(lex_pairs(
            exhaustive_pairs(exhaustive_extreme_floats(), exhaustive_rationals()),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, rm)| log_base_rational_base_1_plus_x_round_valid(x, y, *rm)),
    )
}

// -- (Float, RoundingMode) --

pub fn exhaustive_float_rounding_mode_pair_gen() -> It<(Float, RoundingMode)> {
    Box::new(lex_pairs(exhaustive_floats(), exhaustive_rounding_modes()))
}

pub(crate) fn natural_rounding_from_float_valid(f: &Float, rm: RoundingMode) -> bool {
    match rm {
        Down | Ceiling | Nearest => f.is_finite() || *f == Float::NEGATIVE_INFINITY,
        Up | Floor => f.is_finite() && (f.is_sign_positive() || f.is_negative_zero()),
        Exact => Natural::convertible_from(f),
    }
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_1() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| natural_rounding_from_float_valid(f, *rm)),
    )
}

pub(crate) fn integer_rounding_from_float_valid(f: &Float, rm: RoundingMode) -> bool {
    if rm == Exact {
        Integer::convertible_from(f)
    } else {
        f.is_finite()
    }
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_2() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| integer_rounding_from_float_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_3() -> It<(Float, RoundingMode)> {
    Box::new(lex_pairs(
        exhaustive_nonzero_finite_floats(),
        exhaustive_rounding_modes(),
    ))
}

#[allow(clippy::type_repetition_in_bounds)]
pub(crate) fn unsigned_rounding_from_float_valid<T: PrimitiveUnsigned>(
    f: &Float,
    rm: RoundingMode,
) -> bool
where
    Float: PartialOrd<T>,
    for<'a> T: ConvertibleFrom<&'a Float>,
{
    match rm {
        Floor => f.is_sign_positive() || f.is_negative_zero(),
        Ceiling => *f <= T::MAX,
        Down | Nearest => !f.is_nan(),
        Up => (f.is_sign_positive() || f.is_negative_zero()) && *f <= T::MAX,
        Exact => T::convertible_from(f),
    }
}

#[allow(clippy::type_repetition_in_bounds)]
pub fn exhaustive_float_rounding_mode_pair_gen_var_4<T: PrimitiveUnsigned>()
-> It<(Float, RoundingMode)>
where
    Float: PartialOrd<T>,
    for<'a> T: ConvertibleFrom<&'a Float>,
{
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| unsigned_rounding_from_float_valid::<T>(f, *rm)),
    )
}

#[allow(clippy::type_repetition_in_bounds)]
pub(crate) fn signed_rounding_from_float_valid<T: PrimitiveSigned>(
    f: &Float,
    rm: RoundingMode,
) -> bool
where
    Float: PartialOrd<T>,
    for<'a> T: ConvertibleFrom<&'a Float>,
{
    match rm {
        Floor => *f >= T::MIN,
        Ceiling => *f <= T::MAX,
        Down | Nearest => !f.is_nan(),
        Up => *f >= T::MIN && *f <= T::MAX,
        Exact => T::convertible_from(f),
    }
}

#[allow(clippy::type_repetition_in_bounds)]
pub fn exhaustive_float_rounding_mode_pair_gen_var_5<T: PrimitiveSigned>()
-> It<(Float, RoundingMode)>
where
    Float: PartialOrd<T>,
    for<'a> T: ConvertibleFrom<&'a Float>,
{
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| signed_rounding_from_float_valid::<T>(f, *rm)),
    )
}

#[allow(clippy::type_repetition_in_bounds)]
pub fn exhaustive_float_rounding_mode_pair_gen_var_6<T: PrimitiveFloat>()
-> It<(Float, RoundingMode)>
where
    for<'a> T: ConvertibleFrom<&'a Float>,
{
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| *rm != Exact || T::convertible_from(f)),
    )
}

pub(crate) fn square_round_valid(x: &Float, rm: RoundingMode, extreme: bool) -> bool {
    if rm != Exact {
        true
    } else if extreme {
        x.square_round_ref(Floor).1 == Equal
    } else if let Some(x_prec) = x.get_prec() {
        let square = Float::exact_from(Rational::exact_from(x).square());
        if let Some(min_prec) = square.get_min_prec() {
            x_prec >= min_prec
        } else {
            true
        }
    } else {
        true
    }
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_7() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| square_round_valid(f, *rm, false)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_8() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_floats_with_precision_inclusive_range(1, Limb::WIDTH - 1),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| square_round_valid(f, *rm, false)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_9() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_positive_floats_with_precision(Limb::WIDTH),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| square_round_valid(f, *rm, false)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_10() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_floats_with_precision_inclusive_range(
                Limb::WIDTH + 1,
                (Limb::WIDTH << 1) - 1,
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| square_round_valid(f, *rm, false)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_11() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_positive_floats_with_precision(Limb::WIDTH << 1),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| square_round_valid(f, *rm, false)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_12() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_floats_with_precision_inclusive_range(
                (Limb::WIDTH << 1) + 1,
                Limb::WIDTH * 3 - 1,
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| square_round_valid(f, *rm, false)),
    )
}

pub(crate) fn reciprocal_round_valid(x: &Float, rm: RoundingMode, extreme: bool) -> bool {
    if rm != Exact || *x == 0 {
        true
    } else if extreme {
        x.reciprocal_round_ref(Floor).1 == Equal
    } else if let Some(x_prec) = x.get_prec() {
        if let Ok(reciprocal) = Float::try_from(Rational::exact_from(x).reciprocal()) {
            if let Some(min_prec) = reciprocal.get_min_prec() {
                x_prec >= min_prec
            } else {
                true
            }
        } else {
            false
        }
    } else {
        true
    }
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_13() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| reciprocal_round_valid(f, *rm, false)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_14() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_floats_with_precision_inclusive_range(1, Limb::WIDTH - 1),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| reciprocal_round_valid(f, *rm, false)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_15() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_positive_floats_with_precision(Limb::WIDTH),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| reciprocal_round_valid(f, *rm, false)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_16() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_floats_with_precision_inclusive_range(
                Limb::WIDTH + 1,
                (Limb::WIDTH << 1) - 1,
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| reciprocal_round_valid(f, *rm, false)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_17() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_floats_with_precision_inclusive_range(Limb::WIDTH + 1, u64::MAX),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| reciprocal_round_valid(f, *rm, false)),
    )
}

#[allow(clippy::type_repetition_in_bounds)]
pub fn exhaustive_float_rounding_mode_pair_gen_var_18<T: PrimitiveUnsigned>()
-> It<(Float, RoundingMode)>
where
    Float: PartialOrd<T>,
    for<'a> T: ConvertibleFrom<&'a Float>,
{
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| unsigned_rounding_from_float_valid::<T>(f, *rm)),
    )
}

#[allow(clippy::type_repetition_in_bounds)]
pub fn exhaustive_float_rounding_mode_pair_gen_var_19<T: PrimitiveSigned>()
-> It<(Float, RoundingMode)>
where
    Float: PartialOrd<T>,
    for<'a> T: ConvertibleFrom<&'a Float>,
{
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| signed_rounding_from_float_valid::<T>(f, *rm)),
    )
}

#[allow(clippy::type_repetition_in_bounds)]
pub fn exhaustive_float_rounding_mode_pair_gen_var_20<T: PrimitiveFloat>()
-> It<(Float, RoundingMode)>
where
    for<'a> T: ConvertibleFrom<&'a Float>,
{
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| *rm != Exact || T::convertible_from(f)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_21() -> It<(Float, RoundingMode)> {
    Box::new(lex_pairs(
        exhaustive_extreme_floats(),
        exhaustive_rounding_modes(),
    ))
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_22() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| square_round_valid(f, *rm, true)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_23() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| reciprocal_round_valid(f, *rm, true)),
    )
}

pub(crate) fn sqrt_round_valid(x: &Float, rm: RoundingMode) -> bool {
    rm != Exact || x.sqrt_round_ref(Floor).1 == Equal
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_24() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| sqrt_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_25() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_floats_with_precision_inclusive_range(1, Limb::WIDTH - 1),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| sqrt_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_26() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_positive_floats_with_precision(Limb::WIDTH),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| sqrt_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_27() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_floats_with_precision_inclusive_range(
                Limb::WIDTH + 1,
                (Limb::WIDTH << 1) - 1,
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| sqrt_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_28() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(
            exhaustive_floats_with_precision_inclusive_range((Limb::WIDTH << 1) + 1, u64::MAX),
            exhaustive_rounding_modes(),
        )
        .filter(|(f, rm)| sqrt_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_29() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| sqrt_round_valid(f, *rm)),
    )
}

pub(crate) fn reciprocal_sqrt_round_valid(x: &Float, rm: RoundingMode) -> bool {
    rm != Exact || x.reciprocal_sqrt_round_ref(Floor).1 == Equal
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_30() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| reciprocal_sqrt_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_31() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| reciprocal_sqrt_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_32() -> It<(Float, RoundingMode)> {
    Box::new(lex_pairs(
        exhaustive_floats().filter(|x| *x > 0u32),
        exhaustive_rounding_modes(),
    ))
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_33() -> It<(Float, RoundingMode)> {
    Box::new(lex_pairs(
        exhaustive_finite_floats(),
        exhaustive_rounding_modes(),
    ))
}

pub(crate) fn ln_round_valid(x: &Float, rm: RoundingMode) -> bool {
    rm != Exact || *x <= 0u32 || *x == 1u32
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_34() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| ln_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_35() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| ln_round_valid(f, *rm)),
    )
}

pub(crate) fn ln_1_plus_x_round_valid(x: &Float, rm: RoundingMode) -> bool {
    rm != Exact || *x == 0u32 || *x <= -1i32
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_36() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| ln_1_plus_x_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_37() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| ln_1_plus_x_round_valid(f, *rm)),
    )
}

pub(crate) fn log_base_2_round_valid(x: &Float, rm: RoundingMode) -> bool {
    rm != Exact
        || *x <= 0u32
        || x.is_power_of_2()
            && Float::from_signed_prec(
                i64::from(x.get_exponent().unwrap()) - 1,
                x.get_prec().unwrap(),
            )
            .1 == Equal
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_38() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| log_base_2_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_39() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| log_base_2_round_valid(f, *rm)),
    )
}

pub(crate) fn log_base_power_of_2_round_valid(x: &Float, pow: i64, rm: RoundingMode) -> bool {
    if pow == 0 {
        return false;
    }
    rm != Exact
        || !x.is_finite()
        || *x <= 0u32
        || *x == 1u32
        || x.is_power_of_2()
            && Float::from(i64::from(x.get_exponent().unwrap()) - 1)
                .div_prec(Float::from(pow), x.significant_bits())
                .1
                == Equal
}

pub fn exhaustive_float_signed_rounding_mode_triple_gen_var_7() -> It<(Float, i64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_nonzero_signeds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, pow), rm)| log_base_power_of_2_round_valid(x, pow, rm)),
    ))
}

pub fn exhaustive_float_signed_rounding_mode_triple_gen_var_8() -> It<(Float, i64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_extreme_floats(), exhaustive_nonzero_signeds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, pow), rm)| log_base_power_of_2_round_valid(x, pow, rm)),
    ))
}

pub(crate) fn log_base_round_valid(x: &Float, base: u64, rm: RoundingMode) -> bool {
    if base < 2 {
        return false;
    }
    if rm != Exact || !x.is_finite() || *x <= 0u32 || *x == 1u32 {
        return true;
    }
    if base.is_power_of_2() {
        return log_base_power_of_2_round_valid(x, i64::from(base.trailing_zeros()), rm);
    }
    match rational_log_base(x, base) {
        Some(q) => Float::from_rational_prec_round(q, x.significant_bits(), Nearest).1 == Equal,
        None => false,
    }
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_27() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_floats(),
                primitive_int_increasing_inclusive_range(2, u64::MAX),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, base), rm)| log_base_round_valid(x, base, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_28() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                primitive_int_increasing_inclusive_range(2, u64::MAX),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, base), rm)| log_base_round_valid(x, base, rm)),
    ))
}

pub(crate) fn log_base_1_plus_x_round_valid(x: &Float, base: u64, rm: RoundingMode) -> bool {
    if base < 2 {
        return false;
    }
    if rm != Exact || !x.is_finite() || *x == 0u32 || *x <= -1i32 {
        return true;
    }
    if base.is_power_of_2() {
        return log_base_power_of_2_1_plus_x_round_valid(x, i64::from(base.trailing_zeros()), rm);
    }
    log_base_1_plus_x_rational(x, base)
        .is_some_and(|q| Float::from_rational_prec(q, x.significant_bits()).1 == Equal)
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_32() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_floats(),
                primitive_int_increasing_inclusive_range(2, u64::MAX),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, base), rm)| log_base_1_plus_x_round_valid(x, base, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_33() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                primitive_int_increasing_inclusive_range(2, u64::MAX),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, base), rm)| log_base_1_plus_x_round_valid(x, base, rm)),
    ))
}

pub fn log_base_10_prec_round_valid(x: &Float, prec: u64, rm: RoundingMode) -> bool {
    if rm != Exact || !x.is_finite() || *x <= 0u32 || *x == 1u32 {
        return true;
    }
    // rm == Exact and x is finite, positive, and not 1: exact only when x = 10^n and the integer n
    // is representable at the target precision.
    match float_is_power_of_10(x) {
        Some(n) => Float::from_unsigned_prec_round(n, prec, Nearest).1 == Equal,
        None => false,
    }
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_29() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| log_base_10_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_30() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| log_base_10_prec_round_valid(x, p, rm)),
    ))
}

// Valid inputs to `Float::log_base_10_prec_round`, excluding those with `Exact` (a non-`Exact`
// rounding mode is valid for any `Float`).
pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_31() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(lex_pairs(
        exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
        exhaustive_rounding_modes().filter(|rm| *rm != Exact),
    )))
}

pub(crate) fn log_base_2_1_plus_x_round_valid(x: &Float, rm: RoundingMode) -> bool {
    rm != Exact || *x == 0u32 || *x <= -1i32
}

pub fn log_base_power_of_2_1_plus_x_round_valid(x: &Float, pow: i64, rm: RoundingMode) -> bool {
    if pow == 0 {
        return false;
    }
    rm != Exact
        || !x.is_finite()
        || *x == 0u32
        || *x <= -1i32
        || crate::arithmetic::log_base_2_1_plus_x::log_base_2_1_plus_x_exact(x).is_some_and(|m| {
            Float::from(m)
                .div_prec(Float::from(pow), x.significant_bits())
                .1
                == Equal
        })
}

pub fn exhaustive_float_signed_rounding_mode_triple_gen_var_9() -> It<(Float, i64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_nonzero_signeds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, pow), rm)| log_base_power_of_2_1_plus_x_round_valid(x, pow, rm)),
    ))
}

pub fn exhaustive_float_signed_rounding_mode_triple_gen_var_10() -> It<(Float, i64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_extreme_floats(), exhaustive_nonzero_signeds()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, pow), rm)| log_base_power_of_2_1_plus_x_round_valid(x, pow, rm)),
    ))
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_40() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| log_base_2_1_plus_x_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_41() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| log_base_2_1_plus_x_round_valid(f, *rm)),
    )
}

pub(crate) fn log_base_10_round_valid(x: &Float, rm: RoundingMode) -> bool {
    if rm != Exact || !x.is_finite() || *x <= 0u32 || *x == 1u32 {
        return true;
    }
    match float_is_power_of_10(x) {
        Some(n) => Float::from_unsigned_prec_round(n, x.significant_bits(), Nearest).1 == Equal,
        None => false,
    }
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_42() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| log_base_10_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_43() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| log_base_10_round_valid(f, *rm)),
    )
}

// Valid inputs to `Float::log_base_10_round`, excluding those with `Exact` (a non-`Exact` rounding
// mode is valid for any `Float`).
pub fn exhaustive_float_rounding_mode_pair_gen_var_44() -> It<(Float, RoundingMode)> {
    Box::new(lex_pairs(
        exhaustive_floats(),
        exhaustive_rounding_modes().filter(|rm| *rm != Exact),
    ))
}

pub fn log_base_10_1_plus_x_prec_round_valid(x: &Float, prec: u64, rm: RoundingMode) -> bool {
    if rm != Exact || !x.is_finite() || *x == 0u32 || *x <= -1i32 {
        return true;
    }
    // rm == Exact and x is finite, nonzero, and greater than -1: exact only when 1 + x = 10^m and
    // the result m is representable at the target precision.
    log_base_1_plus_x_rational(x, 10).is_some_and(|q| Float::from_rational_prec(q, prec).1 == Equal)
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_34() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_floats(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| log_base_10_1_plus_x_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_float_unsigned_rounding_mode_triple_gen_var_35() -> It<(Float, u64, RoundingMode)>
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref x, p), rm)| log_base_10_1_plus_x_prec_round_valid(x, p, rm)),
    ))
}

pub(crate) fn log_base_10_1_plus_x_round_valid(x: &Float, rm: RoundingMode) -> bool {
    if rm != Exact || !x.is_finite() || *x == 0u32 || *x <= -1i32 {
        return true;
    }
    log_base_1_plus_x_rational(x, 10)
        .is_some_and(|q| Float::from_rational_prec(q, x.significant_bits()).1 == Equal)
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_45() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| log_base_10_1_plus_x_round_valid(f, *rm)),
    )
}

pub fn exhaustive_float_rounding_mode_pair_gen_var_46() -> It<(Float, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_extreme_floats(), exhaustive_rounding_modes())
            .filter(|(f, rm)| log_base_10_1_plus_x_round_valid(f, *rm)),
    )
}

// -- (Integer, PrimitiveUnsigned, RoundingMode) --

// vars 1 through 2 are in malachite-nz.

pub fn exhaustive_integer_unsigned_rounding_mode_triple_gen_var_3()
-> It<(Integer, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_integers(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| {
            rm != Exact || *n == 0u32 || n.significant_bits() - n.trailing_zeros().unwrap() <= prec
        }),
    ))
}

pub fn exhaustive_integer_unsigned_rounding_mode_triple_gen_var_4()
-> It<(Integer, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(lex_pairs(
        exhaustive_pairs_big_tiny(exhaustive_integers(), exhaustive_positive_primitive_ints()),
        exhaustive_rounding_modes().filter(|rm| *rm != Exact),
    )))
}

// -- (Natural, PrimitiveUnsigned, RoundingMode) --

// var 1 is in malachite-nz.

pub fn exhaustive_natural_unsigned_rounding_mode_triple_gen_var_2()
-> It<(Natural, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_naturals(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| {
            rm != Exact || *n == 0u32 || n.significant_bits() - n.trailing_zeros().unwrap() <= prec
        }),
    ))
}

pub fn exhaustive_natural_unsigned_rounding_mode_triple_gen_var_3()
-> It<(Natural, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(lex_pairs(
        exhaustive_pairs_big_tiny(exhaustive_naturals(), exhaustive_positive_primitive_ints()),
        exhaustive_rounding_modes().filter(|&rm| rm != Exact),
    )))
}

// -- (PrimitiveFloat, PrimitiveUnsigned, RoundingMode) --

// vars 1 through 2 are in malachite-base.

pub fn from_primitive_float_prec_round_valid<T: PrimitiveFloat>(
    x: T,
    p: u64,
    rm: RoundingMode,
) -> bool
where
    Float: From<T>,
{
    set_prec_round_valid(&Float::from(x), p, rm)
}

pub fn exhaustive_primitive_float_unsigned_rounding_mode_triple_gen_var_3<T: PrimitiveFloat>()
-> It<(T, u64, RoundingMode)>
where
    Float: From<T>,
{
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_primitive_floats(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((x, p), rm)| from_primitive_float_prec_round_valid(x, p, rm)),
    ))
}

pub fn exhaustive_primitive_float_unsigned_rounding_mode_triple_gen_var_4<T: PrimitiveFloat>()
-> It<(T, u64, RoundingMode)>
where
    Float: From<T>,
{
    reshape_2_1_to_3(Box::new(lex_pairs(
        exhaustive_pairs_big_tiny(
            exhaustive_primitive_floats(),
            exhaustive_positive_primitive_ints(),
        ),
        exhaustive_rounding_modes().filter(|rm| *rm != Exact),
    )))
}

// -- (PrimitiveSigned, PrimitiveUnsigned, RoundingMode) --

// vars 1 through 2 are in malachite-base.

pub fn exhaustive_signed_unsigned_rounding_mode_triple_gen_var_3<T: PrimitiveSigned>()
-> It<(T, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_signeds::<T>(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| {
            rm != Exact || *n == T::ZERO || n.significant_bits() - n.trailing_zeros() <= prec
        }),
    ))
}

pub fn exhaustive_signed_unsigned_rounding_mode_triple_gen_var_4<T: PrimitiveSigned>()
-> It<(T, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(lex_pairs(
        exhaustive_pairs_big_tiny(
            exhaustive_signeds::<T>(),
            exhaustive_positive_primitive_ints(),
        ),
        exhaustive_rounding_modes().filter(|rm| *rm != Exact),
    )))
}

pub fn exhaustive_signed_unsigned_rounding_mode_triple_gen_var_5() -> It<(i64, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_signeds(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((pow, _), rm)| {
            rm != Exact
                || (Float::MIN_EXPONENT..=Float::MAX_EXPONENT)
                    .contains(&i32::saturating_from(pow).saturating_add(1))
        }),
    ))
}

// -- (PrimitiveUnsigned, PrimitiveUnsigned, RoundingMode) --

// vars 1 through 5 are in malachite-base.

pub fn exhaustive_unsigned_unsigned_rounding_mode_triple_gen_var_6<T: PrimitiveUnsigned>()
-> It<(T, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_unsigneds::<T>(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| {
            rm != Exact || *n == T::ZERO || n.significant_bits() - n.trailing_zeros() <= prec
        }),
    ))
}

pub fn exhaustive_unsigned_unsigned_rounding_mode_triple_gen_var_7<T: PrimitiveUnsigned>()
-> It<(T, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(lex_pairs(
        exhaustive_pairs_big_tiny(
            exhaustive_unsigneds::<T>(),
            exhaustive_positive_primitive_ints(),
        ),
        exhaustive_rounding_modes().filter(|rm| *rm != Exact),
    )))
}

// -- (Rational, PrimitiveUnsigned, RoundingMode) --

pub fn exhaustive_rational_unsigned_rounding_mode_triple_gen_var_1()
-> It<(Rational, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_rationals(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| {
            rm != Exact
                || n.denominator_ref().is_power_of_2()
                    && n.numerator_ref().significant_bits() <= prec
        }),
    ))
}

pub fn exhaustive_rational_unsigned_rounding_mode_triple_gen_var_2()
-> It<(Rational, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(lex_pairs(
        exhaustive_pairs_big_tiny(exhaustive_rationals(), exhaustive_positive_primitive_ints()),
        exhaustive_rounding_modes().filter(|rm| *rm != Exact),
    )))
}

pub fn sqrt_rational_prec_round_valid(x: &Rational, prec: u64, rm: RoundingMode) -> bool {
    rm != Exact || Float::sqrt_rational_prec_round_ref(x, prec, Floor).1 == Equal
}

pub fn exhaustive_rational_unsigned_rounding_mode_triple_gen_var_3()
-> It<(Rational, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_rationals(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| sqrt_rational_prec_round_valid(n, prec, rm)),
    ))
}

pub fn reciprocal_sqrt_rational_prec_round_valid(
    x: &Rational,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    rm != Exact || Float::reciprocal_sqrt_rational_prec_round_ref(x, prec, Floor).1 == Equal
}

pub fn exhaustive_rational_unsigned_rounding_mode_triple_gen_var_4()
-> It<(Rational, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_rationals(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| reciprocal_sqrt_rational_prec_round_valid(n, prec, rm)),
    ))
}

pub fn agm_rational_prec_round_valid(
    x: &Rational,
    y: &Rational,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    rm != Exact
        || *x < 0u32
        || *y < 0u32
        || x == y && Float::from_rational_prec_round_ref(x, prec, Floor).1 == Equal
}

pub fn exhaustive_rational_unsigned_rounding_mode_triple_gen_var_5()
-> It<(Rational, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(
                exhaustive_non_negative_rationals(),
                exhaustive_positive_primitive_ints(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| {
            rm != Exact
                || n.denominator_ref().is_power_of_2()
                    && n.numerator_ref().significant_bits() <= prec
        }),
    ))
}

pub fn ln_rational_prec_round_valid(x: &Rational, _prec: u64, rm: RoundingMode) -> bool {
    rm != Exact || *x <= 0 || *x == 1u32
}

pub fn exhaustive_rational_unsigned_rounding_mode_triple_gen_var_6()
-> It<(Rational, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_rationals(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| ln_rational_prec_round_valid(n, prec, rm)),
    ))
}

pub fn log_base_2_rational_prec_round_valid(x: &Rational, prec: u64, rm: RoundingMode) -> bool {
    // `checked_log_base_2` panics for nonpositive arguments, so the order of these tests matters.
    rm != Exact
        || *x <= 0
        || x.checked_log_base_2()
            .is_some_and(|k| Float::from_signed_prec(k, prec).1 == Equal)
}

pub fn exhaustive_rational_unsigned_rounding_mode_triple_gen_var_7()
-> It<(Rational, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_rationals(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| log_base_2_rational_prec_round_valid(n, prec, rm)),
    ))
}

pub fn log_base_10_rational_prec_round_valid(x: &Rational, prec: u64, rm: RoundingMode) -> bool {
    // `checked_log_base` panics for nonpositive arguments, so the order of these tests matters.
    rm != Exact
        || *x <= 0
        || x.checked_log_base(10)
            .is_some_and(|m| Float::from_signed_prec(m, prec).1 == Equal)
}

pub fn exhaustive_rational_unsigned_rounding_mode_triple_gen_var_9()
-> It<(Rational, u64, RoundingMode)> {
    reshape_2_1_to_3(Box::new(
        lex_pairs(
            exhaustive_pairs_big_tiny(exhaustive_rationals(), exhaustive_positive_primitive_ints()),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, prec), rm)| log_base_10_rational_prec_round_valid(n, prec, rm)),
    ))
}

// -- (Rational, PrimitiveSigned, PrimitiveUnsigned, RoundingMode) --

pub fn log_base_power_of_2_rational_prec_round_valid(
    x: &Rational,
    pow: i64,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if pow == 0 {
        return false;
    }
    // `checked_log_base_2` panics for nonpositive arguments, so the order of these tests matters.
    rm != Exact
        || *x <= 0
        || x.checked_log_base_2()
            .is_some_and(|k| Float::from(k).div_prec(Float::from(pow), prec).1 == Equal)
}

pub fn exhaustive_rational_signed_unsigned_rounding_mode_quadruple_gen_var_1()
-> It<(Rational, i64, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_rationals(),
                exhaustive_nonzero_signeds(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, pow, prec), rm)| {
            log_base_power_of_2_rational_prec_round_valid(n, pow, prec, rm)
        }),
    ))
}

// -- (Rational, PrimitiveUnsigned, PrimitiveUnsigned, RoundingMode) --

pub fn log_base_rational_prec_round_valid(
    x: &Rational,
    base: u64,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if base < 2 {
        return false;
    }
    // `checked_log_base` panics for nonpositive arguments, so the order of these tests matters.
    if rm != Exact || *x <= 0 {
        return true;
    }
    if base.is_power_of_2() {
        return log_base_power_of_2_rational_prec_round_valid(
            x,
            i64::from(base.trailing_zeros()),
            prec,
            rm,
        );
    }
    // rm == Exact and x > 0: exact only when log_base(x) is a rational representable at `prec`.
    rational_log_base_of_rational(x, base)
        .is_some_and(|q| Float::from_rational_prec(q, prec).1 == Equal)
}

pub fn exhaustive_rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_1()
-> It<(Rational, u64, u64, RoundingMode)> {
    reshape_3_1_to_4(Box::new(
        lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_rationals(),
                primitive_int_increasing_inclusive_range(2, u64::MAX),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )
        .filter(|&((ref n, base, prec), rm)| log_base_rational_prec_round_valid(n, base, prec, rm)),
    ))
}

// -- (Rational, Rational, PrimitiveUnsigned, RoundingMode) --

pub fn exhaustive_rational_rational_unsigned_rounding_mode_quadruple_gen_var_1()
-> It<(Rational, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| agm_rational_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn log_base_rational_rational_base_prec_round_valid(
    x: &Rational,
    base: &Rational,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if *base <= 1u32 {
        // The base must be greater than 1.
        return false;
    }
    if rm != Exact || *x <= 0u32 || *x == 1u32 {
        return true;
    }
    // rm == Exact and x is positive and not 1: exact only when log_base(x) is rational and
    // representable at the target precision.
    rational_log_base_rational_rational_base(x, base, prec)
        .is_some_and(|q| Float::from_rational_prec(q, prec).1 == Equal)
}

// All `(Rational, Rational, u64, RoundingMode)` that are valid inputs to
// `Float::log_base_rational_rational_base_prec_round`.
pub fn exhaustive_rational_rational_unsigned_rounding_mode_quadruple_gen_var_2()
-> It<(Rational, Rational, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_xxy_custom_output(
                exhaustive_rationals(),
                exhaustive_positive_primitive_ints::<u64>(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| {
            log_base_rational_rational_base_prec_round_valid(x, y, *prec, *rm)
        }),
    )
}

// -- (Rational, Float, PrimitiveUnsigned, RoundingMode) --

pub fn log_base_rational_float_base_prec_round_valid(
    x: &Rational,
    base: &Float,
    prec: u64,
    rm: RoundingMode,
) -> bool {
    if rm != Exact {
        return true;
    }
    // Special and degenerate inputs (x not positive, x = 1, or base not finite-positive, or base =
    // 1) yield exact results (0, +-infinity, or NaN) and never panic with Exact.
    if *x <= 0u32 || *x == 1u32 || !base.is_finite() || *base <= 0u32 || *base == 1u32 {
        return true;
    }
    log_base_rational_float_base_rational(x, base, prec)
        .is_some_and(|q| Float::from_rational_prec(q, prec).1 == Equal)
}

// All `(Rational, Float, u64, RoundingMode)` that are valid inputs to
// `Float::log_base_rational_float_base_prec_round`.
pub fn exhaustive_rational_float_unsigned_rounding_mode_quadruple_gen_var_1()
-> It<(Rational, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_rationals(),
                exhaustive_floats(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| log_base_rational_float_base_prec_round_valid(x, y, *prec, *rm)),
    )
}

pub fn exhaustive_rational_float_unsigned_rounding_mode_quadruple_gen_var_2()
-> It<(Rational, Float, u64, RoundingMode)> {
    Box::new(
        reshape_3_1_to_4(Box::new(lex_pairs(
            exhaustive_triples_custom_output(
                exhaustive_rationals(),
                exhaustive_extreme_floats(),
                exhaustive_positive_primitive_ints(),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::normal(1),
                BitDistributorOutputType::tiny(),
            ),
            exhaustive_rounding_modes(),
        )))
        .filter(|(x, y, prec, rm)| log_base_rational_float_base_prec_round_valid(x, y, *prec, *rm)),
    )
}

// -- (Rational, RoundingMode) --

// vars 1 through 5 are in malachite-q.

pub fn exhaustive_rational_rounding_mode_pair_gen_var_6() -> It<(Rational, RoundingMode)> {
    Box::new(
        lex_pairs(exhaustive_rationals(), exhaustive_rounding_modes()).filter(|&(ref n, rm)| {
            rm != Exact
                || n.denominator_ref().is_power_of_2() && n.numerator_ref().significant_bits() <= 1
        }),
    )
}
