I translated the code here into C++ as follows
#include <iostream>
using namespace std;
int t = 20;
bool is_evenly_divisible(const int a, const int b) {
for (int i=2; i<=b; ++i) { // Line 1
if (a%i != 0)
return false;
}
return true;
}
void run() {
int i = 10;
while (!is_evenly_divisible(i, t)) {
i += 2;
}
cout << i << endl;
}
int main(int argc, char** argv) {
run();
return 0;
}
With the -O3 flag on compiler g++ 4.8.1 on Mac OSX 10.8.4, I get time 0.568s user time.
Now if I change the counter i in Line 1 in function is_evenly_divisible to size_t, the time suddenly jumps to 1.588s. This persists even if I change all of the variables to size_t, the time increases to 1.646s
What's happening? Shouldn't size_t increase performance rather than decreasing it as it's a more specific type than int?
size_t is commonly used for array indexing and loop counting. Programs that use other types, such as unsigned int, for array indexing may fail on, e.g. 64-bit systems when the index exceeds UINT_MAX or if it relies on 32-bit modular arithmetic.
When writing C code you should always use size_t whenever dealing with memory ranges. The int type on the other hand is basically defined as the size of the (signed) integer value that the host machine can use to most efficiently perform integer arithmetic.
The reason why size_t is encouraged is because it makes your program portable. Typically a program should not need to care how much memory is installed in the machine it is running on. But if the program logic dictates that there will be a lower limit on the number of elements then you could use a smaller index type.
int
is usually the fastest all-round type. This property isn't mandated by the standard, but it's usually the case for today's platforms. We've also got things like cstdint's int_fast32_t
which is more properly guaranteed to be the fastest type that can hold at least 32 bits -- highly recommend them for perf-sensitive code!
size_t
isn't intended to give a fast integer. Its purpose is to provide an integer that can hold the size of the largest sized object your platform's address space can contain. Typically size_t
is equivalent to the largest "native" integer your CPU supports, but it doesn't have to be.
I'm going to guess that you're on a 64-bit platform. Generally a 64-bit platform has about equal perf for 32-bit and 64-bit ops, but you've hit the one place they typically aren't: div/mod can actually be 2-3x slower on a 64-bit integer. In this case if int
is 32-bit and size_t
is 64-bit, it explains the issue nicely.
See Agner Fog's instruction tables document for more info. For Intel's Sandy Bridge platform, it shows 32-bit div has a latency of 20-28 cycles while 64-bit div takes 30-94 cycles.
Size of size_t is implementation-defined and if you are running 64-bit machine most of the compilers would make it 8-byte long.
Operations with 8-byte integers are usually slower than with 4-byte analogs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With