Дорого ли приведение между целыми числами?

Я работаю над проектом, в котором я делаю большой расчет на основе индекса. У меня есть несколько строк, таких как:

let mut current_x: usize = (start.x as isize + i as isize * delta_x) as usize;

start.x а также i являются usizeс и delta_x имеет тип isize, Большая часть моих данных не подписана, поэтому хранить их подписанными не имеет особого смысла. С другой стороны, когда я манипулирую массивом, я получаю много доступа, я должен преобразовать все обратно в usize как видно выше.

Дорого ли приведение между целыми числами? Влияет ли это на производительность во время выполнения вообще?

Существуют ли другие способы упростить / повысить эффективность индексной арифметики?

1 ответ

Решение

Это зависит

В принципе невозможно ответить на ваш вопрос изолированно. Эти типы низкоуровневых вещей могут агрессивно сочетаться с операциями, которые должны произойти в любом случае, поэтому любое количество вложений может изменить поведение. Кроме того, это сильно зависит от вашего процессора; переход на 64-битное число на 8-битном микроконтроллере, вероятно, довольно дорогой!

Мой общий совет - не беспокоиться. Сохраняйте согласованность типов, получайте правильные ответы, затем профилируйте код и устраняйте найденные проблемы.

Прагматично, что ты собираешься делать вместо этого?


Тем не менее, вот некоторые конкретные вещи для x86-64 и Rust 1.18.0.

Тот же размер, меняющийся знак

В основном не влияет. Если бы они были встроены, то вы, вероятно, никогда бы не увидели никакой сборки.

#[inline(never)]
pub fn signed_to_unsigned(i: isize) -> usize {
    i as usize
}

#[inline(never)]
pub fn unsigned_to_signed(i: usize) -> isize {
    i as isize
}

Каждый генерирует сборку

movq    %rdi, %rax
retq

Расширение значения

Они должны расширять значение до нуля или знака, поэтому для заполнения этих дополнительных битов необходимо выполнить какое-то минимальное действие:

#[inline(never)]
pub fn u8_to_u64(i: u8) -> u64 {
    i as u64
}

#[inline(never)]
pub fn i8_to_i64(i: i8) -> i64 {
    i as i64
}

Создает сборку

movzbl  %dil, %eax
retq

movsbq  %dil, %rax
retq

Усечение значения

Усечение снова - просто еще один шаг, в основном без последствий.

#[inline(never)]
pub fn u64_to_u8(i: u64) -> u8 {
    i as u8
}

#[inline(never)]
pub fn i64_to_i8(i: i64) -> i8 {
    i as i8
}

Создает сборку

movl    %edi, %eax
retq

movl    %edi, %eax
retq

Все эти операции сводятся к одной инструкции на x86-64. Затем возникают сложности, связанные с тем, "сколько времени занимает операция", и это еще сложнее.

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