Ceiling of isize/isize

We have:

x: isize;
y: isize

I want to compute ceiling of (x/y).

Is the best way to do this via:

((x as f32) / (y as f32)).ceil() as isize

In a language like C, I'd do int ans = ceil(1.0*x/y) without much thought, but here with all the as casting going no, I'm wondering if there is a better way.

Floating point is unnecessary. You can just use integer division in both Rust and C: (x-1)/y + 1. (See my correction below, thanks to @anon80458984.)

Does isize/isize truncate to 0 or to lower value? Where is this documented in the rust spec?

Ah, whoops, you're right. It truncates to 0. This is also mentioned in the docs for std::ops::Div under impl Div<usize> for usize.

You would have to treat unmatched signs differently. It's best to put this into a helper extension-trait method so that you can invoke x.div_ceil(y). You could also ask the num crate maintainers to add it to their Integer trait.

Though, using the num crate's Integer trait, you could use div_floor and use the formula above: (x-1).div_floor(y) + 1. Actually, comes to think of it, -(-x).div_floor(y) is even shorter (since floor is the opposite of ceil).

1 Like

Note that the f32 approach will produce incorrect (approximated) results for large enough numbers. f64 should be precise for all 32-bit integers, but if isize is 64-bit then there’s no way to do it fully correctly with floating point.

5 Likes

@marcianx , @comex : Thanks for the insights. I'm going to go with the f64 approach (seems most obvious what the code is doing, even if it's verbose.)

Does this work ? I actually more worry about the performance issue caused by floating division

x/y + if x % y != 0 { 1 } else { 0 } 

https://godbolt.org/z/Cw0UAc

2 Likes

Improve upstairs:

x/y + (x%y != 0) as i32
1 Like