gpt4 book ai didi

c - 为什么 uint_least16_t 在 x86_64 中的乘法比 uint_fast16_t 快?

转载 作者:太空狗 更新时间:2023-10-29 16:44:14 27 4
gpt4 key购买 nike

C 标准对 uint_fast*_t 类型家族的定义很不明确。在 gcc-4.4.4 linux x86_64 系统上,类型 uint_fast16_tuint_fast32_t 都是 8 字节大小。然而,8 字节数字的乘法似乎比 4 字节数字的乘法慢得多。下面的一段代码演示了这一点:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int
main ()
{
uint_least16_t p, x;
int count;

p = 1;
for (count = 100000; count != 0; --count)
for (x = 1; x != 50000; ++x)
p*= x;

printf("%"PRIuLEAST16, p);
return 0;
}

在程序上运行时间命令,我得到

real 0m7.606s
user 0m7.557s
sys 0m0.019s

如果我将类型更改为 uint_fast16_t(和 printf 修饰符),时间变为

real 0m12.609s
user 0m12.593s
sys 0m0.009s

那么,如果 stdint.h header 将 uint_fast16_t(以及 uint_fast32_t)定义为 4 字节类型,岂不是更好?

最佳答案

AFAIK 编译器只定义它们自己的 (u)int_(fast/least)XX_t 类型版本,前提是系统尚未定义这些类型。这是因为在单个系统上的所有库/二进制文件中同样定义这些类型非常重要。否则,如果不同的编译器会以不同的方式定义这些类型,则使用 CompilerA 构建的库可能具有与使用 CompilerB 构建的二进制文件不同的 uint_fast32_t 类型,但此二进制文件仍可能链接到库;没有正式的标准要求一个系统的所有可执行代码都必须由同一个编译器构建(实际上在某些系统上,例如 Windows,代码由各种编译器编译是很常见的不同的编译器)。如果现在这个二进制文件调用库的一个函数,事情就会崩溃!

所以问题是:它真的是 GCC 在这里定义了 uint_fast16_t,还是实际上是 Linux(我这里指的是内核)或者甚至是标准 C Lib(在大多数情况下是 glibc)定义了那些类型?因为如果 Linux 或 glibc 定义了这些,那么在该系统上构建的 GCC 别无选择,只能采用它们已经建立的任何约定。对于所有其他可变宽度类型也是如此:charshortintlong长长;所有这些类型在 C 标准 中只有一个最小保证位宽(对于 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.. 在上面的评论中写道:

On x86_64, 32-bit arithmetic should never be slower than 64-bit arithmetic, period.

第二个输出表明不能对 32/16 位算术说同样的话。 16 位运算在 32/64 位 CPU 上可能会慢得多,即使我的 x86 CPU 可以 native 执行 16 位运算;不像其他一些 CPU,例如 PPC,它只能执行 32 位算术。然而,这似乎只适用于我的 CPU 上的乘法运算,当更改代码以进行加法/减法/除法时,16 位和 32 位之间不再有显着差异。

以上结果来自 Intel Core i7 (2.66 GHz),但如果有人感兴趣,我也可以在 Intel Core 2 Duo(上一代 CPU)和 Motorola PowerPC G4 上运行此基准测试。

关于c - 为什么 uint_least16_t 在 x86_64 中的乘法比 uint_fast16_t 快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4116297/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com