Div&mod for `NonZero<T>` - is it worth ACP?

I've noticed that if you divide a non-zero x which is divisible by y then the result is never zero. Suggesting this API:

impl<T: Div + Mod> NonZero<T> {
    fn div_mod(self, divisor: NonZero<T>) -> DivModResult {
        match NonZero::new(self % divisor) {
            Some(remainder) => DivModResult::WithRemainder { quotient: self / divisor, remainder },
            // unchecked is useful here since the optimizer currently doesn't understand this property
            None => DivModResult::Divisible(unsafe { NonZero::new_unchecked(self / divisor) }),
        }
    }
}

pub enum DivModResult<T> {
    Divisible(NonZero<T> /* result of division, the result of mod is 0 here*/),
    WithRemainder { quotient: T, remainder: NonZero<T> },
}

This actually comes up in some decimal formatting code where one needs to remove the trailing zeros from the number after decimal point. (Using non-zero types helps keep track of requirements.)

Maybe there are other uses. Does anyone think this is worth ACP?

An ACP can't hurt. That said, needing the extra type for it makes it feel less likely to me. The ones of these we do have -- like u64 / NonZero<u64> -- don't need the extra type.

(Not to mention that we don't have div_mod methods at all for any integer types, so it's not just an "extend" thing, but a "new" thing.)

3 Likes

Hmm, since the point is to abstract the unchecked operation, maybe it could be:

// ok -> exactly divisible, contains the result of division; `Err` contains the remainder
fn try_exact_div(self, divisor: NonZero<T>) -> Result<Self, Self>

This should enable the callers to compute the division themselves in the err case if they want to.

Also meanwhile I asked GPT for other cases and this also seems to come up in GCD algo.

1 Like