What is the fastest, most memory-saving type?

Asked

Viewed 556 times

5

I am making a game of navinha in C, and therefore need to put in a vector a large amount of projectiles.

These projectiles have at least one position and speed to make calculations, and I’m trying to decide how best to store them in memory for later use.

So there are some questions:

What is the fastest C language type for calculations on modern processors? Which faster type causes less mess in the alignment of a structure and wastes less memory?

This includes variations of types (not int vs float, but also int8_t, uint_fast32_t, double, long double, etc...)

  • 8

    A basic question: Do you really know why you want to optimize this? It seems to me that you are trying to make a premature and unnecessary optimization.

  • 3

    Because I want... boring people, in the OS in English also this persecution. I asked because I’m curious, I saw the new types of C99, and I thought it was cool, and I wanted to learn, I’m not a beginner, but I haven’t used C for many years, and I wanted to exercise my knowledge and learn more about the limits and dark corners of language. I think most C programmers don’t even know that a Struct can be greater than the sum of its members for example.

  • 5

    Is your goal (a) to learn the darkest points of the C language, (b) to perform as well as possible in your game, or (c) to have the memory organization with as little mess as possible? In general, these three things are incompatible with each other and optimizing any of them will likely entail sacrificing the other two.

  • 1

    I don’t see why learning how to reach point (b), or (c) is opposite to point (a). (but I can see how (b) and (c) can be opposites)

  • 4

    The question from @Victor is pertinent and doesn’t sound like stalking. It could save you a few hours or days by not doing an "unnecessary optimization". " Because I want to" is not a rational and objective decision of design. You can’t blame a user who wants to help you just because you mistook it for your question. :)

  • Francisco Junior is that every time I ask performance questions, people drop the premature optimization thing, and they don’t answer. Actually in the English OS (where I asked the same question, and it became flamewar, with people wanting to delete or not the question based on the usefulness of optimization, instead of answering the question) I even asked to delete the question, I will no longer bring exoteric doubts to the OS, I’ll search for myself, and get the answer for myself, the people are very boring and rude.

  • 3

    No one is being rude. @Victor was polite and asked a common question. He just wanted to help. Premature optimization is really a problem, whether you ignore it or not. And if your question caused trouble in the English OS, why didn’t you modify it to post here to avoid the risk of causing the same problem?

  • I posted there, and soon after here, flamewar came after (at the same time that the Victor posted his comment). My nagging is not with Victor personally, I even understand why he asks, but with the whole situation. In the OS in English had moderator and users of very high karma arguing (type, people with more than 100,000 points)

Show 3 more comments

4 answers

9

If you are storing this data in a contiguous region of memory (e.g., an array), then using the type with the smallest size that still "fits" your data would have the best performance. In modern processors, the bottleneck is not in the instructions, but in the cache: one miss cache in L1 "wastes" 10-40 cycles, in L2 more than 600. If you can reduce the number of Misses [by using less memory] at the expense of an additional operation or two (e.g.: types that do not align perfectly in memory, simple conversion of int for float), global performance will be greater.

Disclaimer: I gave my answer based on my theoretical knowledge, but I have not tested it in practice. I cannot say precisely what is the overhead of the above type conversions, and anyway real systems tend to behave surprisingly many times...

  • But I like the answer, it’s the kind of answer I’m looking for :)

9

First of all, be careful not to make premature optimizations because it is very easy to write a complex and "optimized" program that is actually slower than a simpler and more intuitive program. When in doubt use int even is go take care of performance only when you identify a bottleneck in your tests.


But for a more complete answer, the most important thing to keep in mind when choosing an integer type are the rules of coercion when you convert from one type to the other and the rules of what happens in case of overflow (very large or small numbers)

  • For local variables and parameters and function return values prefer to use int. This will compile to use the whole type and "standard" arithmetic operations of your machine.

    This is true even if you are doing math with characters. Not only can you use EOF without overflowing, but you avoid creating a lot of extra instructions to truncate the intermediate values of the accounts back to 8 bits. For example, note how the isalpha functions, etc, of the standard library receive int parameters instead of char.

  • Numbers unsigned are useful if you want well-defined overflow behavior (wrap-Around) or if you are working with bit masks. Otherwise, avoid using them, even if you know that the value that interests you is always positive. -1 give underflow is a source of a lot of headache (eg, for(unsigned i=N; i>=0; i--) becomes an infinite loop).

  • If you are storing a lot of values in a vector the width of the integers gains more importance (a char vector spends far less space than an int vector) and the performance of operations is less important (You will extract these values to a local registrar/variable before doing any accounts on them).

  • Avoid fixed size types like int8_t etc unless you are doing something that requires an entire exactly that size. Not only are these types full of extra Casts (see the previous example of int vs char) but these Casts can be more expensive if the size is not something common in your architecture.

  • If the values of your integers can be very large, at a point where 32-bit or 64-bit makes a difference you have to be more careful. There is more than one alternative you can use (long long, bignum library, vector of smaller integers, etc.) and the best solution will depend on your problem, compiler, etc.

  • In reality, int is always 32 bits, long long is always 64, and long is 64 compiling with gcc for 64 bits. In Visual Studio, long is 32 bits even on 64 architectures.

3

In this case, it’s not the question of faster, but the question of which kind makes the most sense.

In general, working with integers will always be more efficient than working with letters, but from a programming point of view, unless you are working with something that requires extreme performance, it is best to use what is most comfortable.

In C, when it makes sense, it is useful for example to use struct for more complex data instead of just using an array with vectors. A struct, for example, can store information like the last data accessed from a list of an array (or linked list) and, as not as efficient as using pure data, can be extremely efficient when the amount of data is greater, because you would have already curled the die, instead of having to sweep the entire list looking for the data you wanted.

Okay, you really want to know which one is faster? Well, when in doubt, it’s usually faster data than occupying less data in memory, or data that can be operated by bitwise operations. Even in this case, it is not only the data that matters, but how the data will be used.

2

For integer numbers, the most indicated always the word size number of the processor. It will align right in memory everything else. Since this changes from compiler to compiler, the most guaranteed is to use ptrdiff_t and size_t, Standard typedefs for whole types with and without signal respectively, defined in stddef.h. Already to floating point, there is no reason not to use double. In any modern processor it is efficient, and it is not justified to use the float.

  • 1

    I would like to add your answer, that GPU (video processor) uses just float, and in this case save data going to the video processor in float is best.

  • True, but in general you do all the calculations in the CPU, where the extra precision can make the difference, and only in the end plays the result in the GPU. I think in the general case it pays to do so, but obviously each case is a case.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.