Как выполнять арифметические операции с BitSlices?

Используя битвек ящик, скажем, у меня есть две BitSlices:

let num1: &BitSlice = 10.view_bits::<Lsb0>();
let num2: &BitSlice = 9.view_bits::<Lsb0>();

Есть ли способ запустить с ними битовые арифметические операции, такие как num1 - num2?

У меня есть ограничение работы в среде no-std, и битовые фрагменты могут быть довольно большими, поэтому я не могу преобразовать их в числа, выполнить операцию и преобразовать обратно в битовое представление.

Можно ли использовать на ночь?

Chayim Friedman 17.05.2022 12:03

Проблема будет заключаться в том, что вам нужно будет создать произвольно большое Bitvec в результате сложений и умножений, что будет сложно в no_std.

Peter Hall 17.05.2022 12:49

@ChayimFriedman Я бы предпочел не делать этого, так как в прошлом я получал непонятные ошибки при попытке скомпилировать встроенную цель с nightly. Но, пожалуйста, поделитесь, если у вас есть идея, как это сделать с nightly.

jhk999 17.05.2022 12:50

@PeterHall На самом деле меня интересует только вычитание на практике. Но для меня приемлемо и решение, которое паникует при переполнении.

jhk999 17.05.2022 12:51

Так почему бы просто не вычесть биты, используя алгоритм длинного вычитания?

Peter Hall 17.05.2022 13:28

Вы можете вычесть на месте, но вам понадобится выделение не на месте.

Chayim Friedman 17.05.2022 13:28
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
2
6
61
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

bitvec раньше включал добавление и вычитание, но они были удалены в версии 0.18. Кроме того, на BitSlice никогда не было вычитания, только сложение. Хотя было упомянуто, что они должны быть перемещены в отдельный ящик, мне не удалось найти такой ящик. Значит, вам нужно реализовать это самостоятельно.

Самый простой (хотя определенно не самый эффективный) способ — пройтись по битам и выполнить операцию.

Например, дополнение (адаптировано из кода версии 0.17.4):

/// May overflow.
pub fn add_assign(lhs: &mut BitSlice, rhs: &BitSlice) {
    fn add_with_carry(a: bool, b: bool, carry: bool) -> (bool, bool) {
        let result = u8::from(a) + u8::from(b) + u8::from(carry);
        ((result & 0b01) != 0, (result & 0b10) != 0)
    }

    let mut carry = false;
    let extended_rhs = rhs.iter().by_vals().rev().chain(core::iter::repeat(false));
    for (mut lhs_bit, rhs_bit) in lhs.iter_mut().rev().zip(extended_rhs) {
        (*lhs_bit, carry) = add_with_carry(*lhs_bit, rhs_bit, carry);
    }
}

Обратите внимание, что вы не можете предотвратить переполнение, если не можете расширить срез, а для этого требуется BitVec и поддержка распределения.

Благодарю вас! Только одна последняя вещь. Я не могу понять, как вызвать эту функцию. add_assign(&mut lhs, rhs) не получается. Не могли бы вы помочь мне с этим?

jhk999 17.05.2022 15:35

@ jhk999 Какие бывают типы lhs и rhs?

Chayim Friedman 17.05.2022 15:36
let lhs = &mut bits![1; 5]; let rhs = bits![1; 5];
jhk999 17.05.2022 15:40

Вам нужно lhs быть bits![mut 1; 5]. &mut bits![...] производит &mut &BitSlice. См. bits! документы.

Chayim Friedman 17.05.2022 16:30

Для полноты я также добавлю свою собственную функцию для вычитания:

pub fn subtract(lhs: &mut BitSlice, rhs: &BitSlice) {
    let mut borrow = false;
    for (mut l, r) in lhs
        .iter_mut()
        .rev()
        .zip(rhs.iter().by_vals().rev().chain(core::iter::repeat(false)))
    {
        if borrow {
            *l = !(*l);
            borrow = *l;
        }
        *l = match (*l, r) {
            (true, false) => true,
            (false, true) => {
                borrow = true;
                true
            }
            (_, _) => false,
        };
    }
}

Я могу сделать определенные предположения, такие как порядок битов и lhs >= rhs для моего варианта использования, поэтому, если вы собираетесь скопировать этот код, рассмотрите и такие случаи.

Другие вопросы по теме