2 ms·
I'd argue this is about safely summing up numbers, not correctly. For example, this is the proposed rust solution (imho the most readable): fn sum_up_numb
by wongarsu 2y ago
I'd argue this is about safely summing up numbers, not correctly.
For example, this is the proposed rust solution (imho the most readable):
fn sum_up_numbers_correctly(numbers: &[i32]) -> Option<i32> {
let mut sum: i32 = 0;
for i in numbers {
sum = sum.checked_add(*i)?;
}
Some(sum)
}
If you try to sum [i32::MAX, i32::MIN, 2] this will return None, while the naive wrapping addition would have returned 1. I'd call None a safe result, it's the algorithm bailing out when it's unsure, and 1 the correct result.
The upside of wrapping addition is that you can overflow as often as you want, as long as the result is within the range of the type, the result (of addition and subtraction) is correct. The downside is that you don't know if the result is within range. So you trade between correctly handling a larger range of inputs with wrapping or being more certain of the result with checked overflow.
My preferred solution would have been just upcasting. If we make sum an i64 we know it can't overflow the intermediate if you sum less than 2^32 i32 numbers, and on a 64 bit machine you lose basically nothing by doing that. Keep the checked_add if you are concerned about people summing extremely long lists of numbers
fn sum_up_numbers_correctly(numbers: &[i32]) -> Option<i32> {
let mut sum: i64 = 0;
for i in numbers {
sum = sum.checked_add(*i as i64)?;
}
Some(sum.try_into().ok()?)
}
(the try_into().ok() turns values that overflow i32 into None).
When summing i64 you can do the same trick by summing into an i128