Должен ли я использовать i32 или i64 на 64-битной машине?

main.rs

#![feature(core_intrinsics)]
fn print_type_of<T>(_: &T) {
    println!("{}", unsafe { std::intrinsics::type_name::<T>() });
}

fn main() {
    let x = 93;
    let y = 93.1;

    print_type_of(&x);
    print_type_of(&y);
}

Если я скомпилирую с «rustc +nightly ./main.rs», я получу следующий вывод:

$ ./main

i32
f64

Я запускаю Linux-машину x86_64. Переменные с плавающей запятой по умолчанию имеют двойную точность, и это хорошо. Почему целые числа имеют длину всего 4 байта? Что я должен использовать? Если мне не нужен i64, я должен использовать i32? i32 лучше по производительности?


person Giorgio Napolitano    schedule 04.08.2018    source источник
comment
Я что-то пропустил или вы перепутали i64 и f64 ?   -  person Stargateur    schedule 04.08.2018
comment
@Stargateur: Нет, не знал. Он указывает, что тип по умолчанию неукрашенного литерала с плавающей запятой является 64-битным типом, и поэтому задается вопросом, почему тип по умолчанию неукрашенного целочисленного литерала также не является 64-битным.   -  person Benjamin Lindley    schedule 04.08.2018
comment
Вам может быть полезно прочитать C++ int vs long long в 64 битовая машина. C++ имеет дополнительное усложнение целых чисел переменного размера (в Rust usize и isize — единственные типы с этим свойством).   -  person trentcl    schedule 04.08.2018


Ответы (3)


i32 лучше по производительности?

Это вообще какая-то тонкая вещь. Если мы посмотрим на некоторые недавние тесты на уровне инструкций, например, для SkylakeX по большей части очень явное отсутствие разницы между 64-битными и 32-битными инструкциями. Исключением является деление, 64-битное деление медленнее, чем 32-битное, даже при делении одних и тех же значений (деление — одна из немногих инструкций с переменным временем, которые зависят от значений ее входов).

Использование i64 для данных также делает автоматическую векторизацию менее эффективной — это также одно из редких мест, где данные размером менее 32 бит используются помимо оптимизации размера данных. Конечно, размер данных также имеет значение для вопроса i32 и i64, работа со значительными массивами i64 может быть медленнее только потому, что они больше, поэтому требуется больше места в кешах и (если применимо) большая пропускная способность. Так что если вопрос [i32] против [i64], то это имеет значение.

Еще более тонким является тот факт, что использование 64-битных операций означает, что в среднем код будет содержать больше префиксов REX, что делает код немного менее плотным, а это означает, что меньшая его часть будет помещаться в кэше кода L1 одновременно. Хотя это небольшой эффект. Просто наличие 64-битных переменных в коде не является проблемой.

Несмотря на все это, определенно не злоупотребляйте i32, особенно там, где вам действительно нужен usize. Например, не делайте этого:

// don't do this
for i in 0i32 .. data.len() as i32 { 
  sum += data[i as usize]; 
}

Это приводит к значительному снижению производительности. Мало того, что теперь в цикле есть бессмысленное расширение знака, оно также побеждает устранение проверки границ и автоматическую векторизацию. Но, конечно, в первую очередь нет причин писать такой код, это неестественно и сложнее, чем сделать это правильно.

person harold    schedule 04.08.2018

Язык программирования Rust говорит:

[...] целые типы по умолчанию имеют значение i32: этот тип, как правило, самый быстрый, даже в 64-битных системах.

И (в следующем раздел):

Тип по умолчанию — f64, потому что на современных процессорах он имеет примерно ту же скорость, что и f32, но обеспечивает большую точность.


Однако это довольно упрощенно. Какой целочисленный тип следует использовать, во многом зависит от вашей программы. Не думайте о скорости при первоначальном написании программы, если вы уже не знаете, что скорость будет проблемой. В подавляющем большинстве кодов скорость не имеет значения: даже в приложениях, критически важных для производительности, большая часть кода является холодным кодом. Напротив, правильность всегда важна.

Также обратите внимание, что только неограниченные числовые переменные по умолчанию имеют значения i32/f64. Как только вы используете переменную в контексте, где требуется определенный числовой тип, компилятор использует этот тип.

person Lukas Kalbertodt    schedule 04.08.2018

Прежде всего, вы должны разработать свое приложение для ваших нужд/требований. То есть, если вам нужны «большие» целые числа, используйте большие типы. Если они вам не нужны, используйте маленькие шрифты.

ЕСЛИ вы столкнулись с какими-либо проблемами с производительностью (И ТОЛЬКО ТОГДА), вы должны настроить типы на то, что вам может не понадобиться по требованию.

person iPirat    schedule 04.08.2018