加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

x86_64:为什么uint_least16_t比uint_fast16_t快(用于乘法)

发布时间:2020-12-14 04:05:33 所属栏目:Windows 来源:网络整理
导读:关于uint_fast * _t系列类型,C标准还不太清楚.在 gcc-4.4.4 linux x86_64系统上,类型uint_fast16_t和uint_fast32_t的大小都是8个字节.但是,8字节数的乘法似乎比4字节数的乘法慢得多.以下代码演示了: #include stdio.h#include stdint.h#include inttypes.hi
关于uint_fast * _t系列类型,C标准还不太清楚.在 gcc-4.4.4 linux x86_64系统上,类型uint_fast16_t和uint_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;
}

在程序上运行time命令,我明白了

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

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

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

那么,如果stdint.h头文件将uint_fast16_t(以及uint_fast32_t)定义为4字节类型,那会不会更好?

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

所以问题是:这里真的是GCC定义uint_fast16_t,还是实际上是Linux(我的意思是这里的内核),甚至可能是标准C Lib(大多数情况下是glibc),它定义了那些类型?因为如果Linux或glibc定义了这些,那么建立在该系统上的GCC除了采用它们已经建立的任何约定之外别无选择.对于所有其他可变宽度类型也是如此:char,short,int,long,long long;所有这些类型在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位算术不能说同样的事情.即使我的x86 CPU本身可以执行16位运算,32位算术在32/64位CPU上也会明显变慢.与其他一些CPU不同,例如PPC,它只能执行32位算术.但是,这似乎只适用于我的CPU上的乘法,当更改代码进行加/减/除时,16和32位之间没有显着差异.

以上结果来自英特尔酷睿i7(2.66 GHz),但如果有人感兴趣,我也可以在英特尔酷睿2双核处理器(旧一代CPU)和摩托罗拉PowerPC G4上运行此基准测试.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读