8

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);
}

If I compile with "rustc +nightly ./main.rs", i got this output:

$ ./main

i32
f64

I run a x86_64 Linux machine. Floating point variables are double precision by default, which is good. Why integers are only 4 bytes? Which should I use? If I don't need i64 should I use i32? Are i32 better for performance?

  • Did I miss something or you confuse `i64` and `f64` ? – Stargateur Aug 04 '18 at 13:08
  • 3
    @Stargateur: No, he didn't. He's pointing out that the default type of an unadorned floating point literal is a 64 bit type, and so is wondering why the default type of an unadorned integer literal is not also 64 bits. – Benjamin Lindley Aug 04 '18 at 14:02
  • 2
    You may find it helpful to read [C++ int vs long long in 64 bit machine](https://stackoverflow.com/questions/39779880/c-int-vs-long-long-in-64-bit-machine). C++ has the added complication of variable size integers (in Rust `usize` and `isize` are the only types with this property). – trent Aug 04 '18 at 15:21

3 Answers3

18

Are i32 better for performance?

That's actually kind of a subtle thing. If we look up some recent instruction-level benchmarks for example for SkylakeX, there is for the most part a very clear lack of difference between 64bit and 32bit instructions. An exception to that is division, 64bit division is slower than 32bit division, even when dividing the same values (division is one of the few variable-time instructions that depend on the values of its inputs).

Using i64 for data also makes auto-vectorization less effective - this is also one of the rare places where data smaller than 32bit has a use beyond data-size optimization. Of course the data size also matters for the i32 vs i64 question, working with sizable arrays of i64's can easily be slower just because it's bigger, therefore costing more space in the caches and (if applicable) more bandwidth. So if the question is [i32] vs [i64], then it matters.

Even more subtle is the fact that using 64bit operations means that the code will contains more REX prefixes on average, making the code slightly less dense meaning that less of it will fit in the L1 code cache at once. This is a small effect though. Just having some 64bit variables in the code is not a problem.

Despite all that, definitely don't overuse i32, especially in places where you should really have an usize. For example, do not do this:

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

This causes a large performance regression. Not only is there a pointless sign-extension in the loop now, it also defeats bounds check elimination and auto-vectorization. But of course there is no reason to write code like that in the first place, it's unnatural and harder than doing it right.

harold
  • 61,398
  • 6
  • 86
  • 164
14

The Rust Programming Language says:

[...] integer types default to i32: this type is generally the fastest, even on 64-bit systems.

And (in the next section):

The default type is f64 because on modern CPUs it’s roughly the same speed as f32 but is capable of more precision.


However, this is fairly simplified. What integer type you should use depends a lot on your program. Don't think about speed when initially writing the program, unless you already know that speed will be a problem. In the vast majority of code, speed doesn't matter: even in performance critical applications, most code is cold code. In contrast, correctness always matters.

Also note that only unconstrained numeric variables default to i32/f64. As soon as you use the variable in a context where a specific numeric type is needed, the compiler uses that type.

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
0

First of all, you should design your application for your needs/requirements. I.e., if you need „large“ integers, use large types. If you don’t need them, you should use small types.

IF you encounter any performance issues (AND ONLY THEN) should you adjust types to something you may not need by requirement.

iPirat
  • 2,197
  • 1
  • 17
  • 30