joshlf
joshlf

Reputation: 23617

Round a Rational64 down to next multiple of a fraction without overflow?

I'm representing numbers as ratios of signed 64-bit integers using the num-rational crate's Rational64 type. I'm trying to round a number down to the next multiple of another number, and I'm getting integer overflow issues when I do it in either of the two obvious ways. Note that both of the numbers may be fractions.

Normalize to an integer

extern crate num_rational;
extern crate num_traits;

use num_rational::Rational64;
use num_traits::identities::Zero;

fn round(mut n: Rational64, increment: Rational64) -> Rational64 {
    let rem = n % increment;
    if !rem.is_zero() {
        // normalize to a multiple of the increment, round down
        // to the next integer, and then undo the normalization
        n = (n * increment.recip()).trunc() * increment;
    }
    n
}

fn main() {
    let a = Rational64::new(10_000_676_909_441, 8_872_044_800_000_000);
    let b = Rational64::new(1, 1_000_000);
    let c = round(a, b);
    println!("{}", c);
}

(playground)

Subtract the remainder

extern crate num_rational;
extern crate num_traits;

use num_rational::Rational64;
use num_traits::identities::Zero;

fn round(mut n: Rational64, increment: Rational64) -> Rational64 {
    let rem = n % increment;
    if !rem.is_zero() {
        n -= rem;
    }
    n
}

fn main() {
    let a = Rational64::new(10_000_676_909_441, 8_872_044_800_000_000);
    let b = Rational64::new(1, 1_000_000);
    let c = round(a, b);
    println!("{}", c);
}

(playground)

Is there a way to make it so that n is rounded down to a multiple of increment such that integer overflow is less likely? It's fine if I have to extract the numerator and denominator (both Rust i64 types) and do math on them directly.

Upvotes: 3

Views: 312

Answers (0)

Related Questions