Как мне добавить целое число со знаком к целому числу без знака в Rust, проверяя переполнение без знака?

#rust #unsigned #signed

#Ржавчина #без знака #подписано

Вопрос:

Я хочу добавить an isize в a usize и включить проверку границ, чтобы результат не выходил за пределы a usize . Как это можно сделать?

Ответ №1:

Вы могли бы использовать комбинацию isize::is_negative() , isize::wrapping_abs() , usize::checked_add() и usize::checked_sub() .

 const fn add(lhs: usize, rhs: isize) -> Option<usize> {
    if rhs.is_negative() {
        lhs.checked_sub(rhs.wrapping_abs() as usize)
    } else {
        lhs.checked_add(rhs as usize)
    }
}
 

Почему isize::is_negative() vs rhs < 0 ? В данном случае это ничего не меняет, так как логические операции с литералами считаются постоянными выражениями.

Однако, хотя это разрешено для литералов, это вообще запрещено, поскольку методы признаков не могут быть const . Так что, если бы у вас был тип обертывания, например Foo(isize) , тогда было бы запрещено говорить foo < Foo(0) в контексте const. Хотя можно было бы сказать foo.is_negative() , что as Foo все еще может реализовать a const fn is_negative() .

Да, вы все еще могли бы сказать foo.0 < 0 , но это не то, что я пытался сказать.

Комментарии:

1. джей Си, есть ли причина предпочесть is_negative() < 0 это?

2. Не будет ли это переполняться, если rhs есть isize::MIN ?

3. Использование x < 0 тоже хорошо, и да, оно переполняется, я обновил ответ для использования wrapping_abs() .

4. @kmdreko Я добавил некоторый контекст к почему is_negative() vs < 0

5. @goose121 No. isize::MIN равно 0b1000..000 и -(isize::MIN 1) равно 0b0111..1111 итак isize::MIN as usize == (isize::MIN 1) as usize 1 .

Ответ №2:

Одним из способов сделать это было бы использовать функцию, подобную следующей:

 fn signed_unsigned_add(x: usize, y: isize) -> usize {
    let (n, overflow) = x.overflowing_add(y as usize);
    if (y >= 0) ^ overflow {
        n
    } else {
        panic!(
            "signed   unsigned addition overflow: {}   {}",
            x,
            y,
        )
    }
}
 

Это использует тот факт, что такое дополнение, если рассматривать его с точки зрения чисел без знака, должно «переполняться» (т. Е. Демонстрировать поведение дополнения к двум) только тогда, когда число без знака отрицательно, и если оно этого не делает, когда число отрицательно, это указывает на недостаточный поток.