Компиляторы AFAIK определяют свои собственные версии типов (u)int_(fast/least)XX_t
, только если они еще не определены системой. Это потому, что очень важно, чтобы эти типы были одинаково определены во всех библиотеках / двоичных файлах в одной системе. В противном случае, если разные компиляторы будут определять эти типы по-разному, библиотека, созданная с помощью CompilerA, может иметь тип uint_fast32_t
, отличный от двоичного файла, созданного с помощью CompilerB, но этот двоичный файл все еще может ссылаться на библиотеку; не существует формального стандартного требования о том, что весь исполняемый код системы должен быть собран одним и тем же компилятором (фактически, в некоторых системах, например, в Windows, довольно распространено, что код был скомпилирован всеми видами различных компиляторы). Если теперь этот двоичный файл вызывает функцию библиотеки, вещи сломаются!
Итак, вопрос в том, действительно ли GCC определяет здесь uint_fast16_t, или это на самом деле Linux (я имею в виду ядро здесь) или, может быть, даже Standard C Lib (в большинстве случаев glibc), который определяет эти типы? Поскольку, если Linux или glibc определяют их, GCC, построенный на этой системе, не имеет другого выбора, кроме как принять те соглашения, которые они установили. То же самое верно и для всех других типов переменной ширины: char
, short
, int
, long
, long long
; все эти типы имеют только минимальную гарантированную битовую ширину в C Standard (а для int
это на самом деле 16 бит, поэтому на платформах, где int
32-битный, он уже намного больше, чем по требованию стандарта).
Кроме этого, мне действительно интересно, что не так с вашим CPU / компилятором / системой. В моей системе 64-битное умножение одинаково быстро для 32-битного умножения. Я изменил ваш код для тестирования 16, 32 и 64 бит:
#include <time.h>
#include <stdio.h>
#include <inttypes.h>
#define RUNS 100000
#define TEST(type) \
static type test ## type () \
{ \
int count; \
type p, x; \
\
p = 1; \
for (count = RUNS; count != 0; count--) { \
for (x = 1; x != 50000; x++) { \
p *= x; \
} \
} \
return p; \
}
TEST(uint16_t)
TEST(uint32_t)
TEST(uint64_t)
#define CLOCK_TO_SEC(clock) ((double)clockTime / CLOCKS_PER_SEC)
#define RUN_TEST(type) \
{ \
clock_t clockTime; \
unsigned long long result; \
\
clockTime = clock(); \
result = test ## type (); \
clockTime = clock() - clockTime; \
printf("Test %s took %2.4f s. (%llu)\n", \
#type, CLOCK_TO_SEC(clockTime), result \
); \
}
int main ()
{
RUN_TEST(uint16_t)
RUN_TEST(uint32_t)
RUN_TEST(uint64_t)
return 0;
}
Используя неоптимизированный код (-O0), я получаю:
Test uint16_t took 13.6286 s. (0)
Test uint32_t took 12.5881 s. (0)
Test uint64_t took 12.6006 s. (0)
Используя оптимизированный код (-O3), я получаю:
Test uint16_t took 13.6385 s. (0)
Test uint32_t took 4.5455 s. (0)
Test uint64_t took 4.5382 s. (0)
Второй вывод довольно интересный. @R .. написал в комментарии выше:
В x86_64 32-битная арифметика никогда не должна быть медленнее 64-битной
арифметика, точка.
Второй вывод показывает, что то же самое нельзя сказать о 32/16-битной арифметике. 16-разрядная арифметика может быть значительно медленнее на 32/64-разрядном процессоре, хотя мой процессор x86 может выполнять 16-разрядную арифметику изначально; в отличие от некоторых других процессоров, таких как, например, PPC, которые могут выполнять только 32-битную арифметику. Однако, похоже, что это применимо только к умножению на моем ЦП, когда при изменении кода на сложение / вычитание / деление больше не будет существенной разницы между 16 и 32 битами.
Приведенные выше результаты получены с Intel Core i7 (2,66 ГГц), но, если кому-то интересно, я могу запустить этот тест также на Intel Core 2 Duo (на одно поколение процессора старше) и на Motorola PowerPC G4.