Дорого ли приведение между целыми числами?
Я работаю над проектом, в котором я делаю большой расчет на основе индекса. У меня есть несколько строк, таких как:
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. Затем возникают сложности, связанные с тем, "сколько времени занимает операция", и это еще сложнее.