Трябва ли да използвам 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

Пускам x86_64 Linux машина. Променливите с плаваща запетая са с двойна точност по подразбиране, което е добре. Защо целите числа са само 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 срещу 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