【问题标题】:Is it faster to multiply low numbers in C/C++ (as opposed to high numbers)?在 C/C++ 中乘以小数(而不是大数)是否更快?
【发布时间】:2018-03-08 06:50:59
【问题描述】:

问题示例:

计算 123 * 456 比计算 123456 * 7890 快吗?还是一样的速度?

我想知道 32 位无符号整数,但我不会忽略其他类型(64 位、有符号、浮点数等)的答案。如果不同,是什么原因造成的?位是否为 0/1?

编辑:如果有区别,我应该澄清我指的是任何数字(两个低于 100 的随机数与两个高于 1000 的随机数)

【问题讨论】:

  • 这真的不是一般基础可以回答的问题,因为它高度依赖于目标平台和可能的编译器。对于您的特定编译器和目标,您始终可以将每个乘法执行一百万次,并检查执行它所需的时间。
  • 没有 C/C++。 C 和 C++ 是不同的语言。两者都没有给你任何速度保证。你需要问一个关于你的平台的问题,而不是关于编程语言的问题。
  • 你至少需要指定CPU。这是一个关于硬件和架构的问题。与 C++ 无关。
  • AFAIK,一个 C 编译器和一个 C++ 编译器(内部)没有比intunsigned 更小的类型的乘法。因此,如果至少有一个值存储在变量中,则 123 * 456 和 123456 * 7890 将编译为 int * int。 (常量在编译时相乘。)例外是优化 2 的幂,如前所述。
  • 有些原子处理器的 8 位 division 效率更高……因此 gcc 的 -m8bit-idiv,但它更多的是例外而不是规则。你会发现这种事情的一个地方是在极其精简的指令集架构中,其中乘法是一条微编码指令。嗯。让我想知道:“nand accumulator bit with current bitstack and swap bit-stacks if false”机器图灵完成了吗?

标签: c++ c optimization integer-arithmetic


【解决方案1】:

对于每个编译器/实现/版本和CPU 我听说过,用于乘法特定整数大小的 CPU 操作码需要一定数量的时钟周期,而与所涉及的数量无关不同大小的数据相乘,在某些 CPU 上执行不同(例如,AMD K7 对于 16 位 IMUL 有 3 个周期延迟,而对于 32 位则有 4 个周期)。

有可能在某些架构和编译器/标志组合中,像long long int 这样的类型的位数可能比 CPU 操作码在一条指令中可以操作的位数多,因此编译器可能会发出代码分阶段进行乘法运算,这将比 CPU 支持的类型的乘法运算要慢。但同样,在运行时以更广泛的类型存储的小值不太可能与较大的值有任何不同的处理或执行。

话虽如此,如果一个或两个值都是编译时常量,编译器能够避免 CPU 乘法运算符并针对某些值优化加法或位移运算符(例如 1 显然是一个无操作, 任一侧 0 ==> 0 结果,* 4 有时可以实现为<< 2)。没有什么特别的停止技术,如用于较大数字的位移,但是可以将较小百分比的此类数字优化到相同程度(例如,有更多的 2 的幂 - 可以使用向左位移来执行乘法 - 0 到 1000 之间,而不是 1000 到 2000 之间)。

【讨论】:

    【解决方案2】:

    这高度依赖于处理器架构和型号。

    在过去(大约 1980-1990 年),两个数字中的个数会是一个因素 - 一个数越多,相乘所需的时间越长 [在符号调整后,因此乘以 -1 不是比乘以 1 慢,但乘以 32767(15 个)明显慢于乘以 17(2 个)]。那是因为乘法本质上是:

    unsigned int multiply(unsigned int a, unsigned int b)
    {  
        res = 0;  
        for(number of bits)
        {
            if (b & 1)
            {
               res += a;
            }
            a <<= 1;
            b >>= 1;
        }
    }
    

    在现代处理器中,乘法无论哪种方式都非常快,但 64 位乘法可能比 32 位值慢一个或两个时钟周期。仅仅因为现代处理器可以“负担”在一个周期内完成此操作的整个逻辑 - 无论是在晶体管本身的速度方面,还是在这些晶体管占用的面积方面。

    此外,在过去,通常有执行 16 x 16 -> 32 位结果的指令,但如果您想要 32 x 32 -> 32(或 64),编译器将不得不调用库函数 [或内联这样的功能]。今天,我不知道任何现代高端处理器 [x86, ARM, PowerPC] 至少不能做到 64 x 64 -> 64,有些做到 64 x 64 -> 128,所有这些都在一条指令中(不是总是一个循环 tho')。

    请注意,我完全忽略了“如果数据在缓存中是一个重要因素”这一事实。是的,这是一个因素——这有点像在以 200 公里/小时的速度行驶时忽略风阻——这在现实世界中根本不会被忽略。但是,对于本次讨论而言,这并不重要。就像制造跑车的人关心空气动力学一样,要让复杂(或简单)的软件快速运行,需要一定程度地关心缓存内容。

    【讨论】:

    • 如今缓存未命中的成本也远高于 ALU 操作(在台式机和笔记本电脑处理器上)
    • 这完全取决于你问谁。我不会将 AVR 或 PIC 称为现代(它们实际上来自 1970 年代至 1980 年代),但它们今天通过虚假营销被当作现代出售。看看整个 Arduino 炒作。
    • @Lundin 添加了“高端”的措辞,以说明存在容量较低的处理器(这在某些情况下是完美的,因为它们成本低、功耗低等)。
    【解决方案3】:

    出于所有意图和目的,速度相同(即使计算速度存在差异,它们也是无法衡量的)。如果您好奇,这里有一个基准测试不同 CPU 操作的参考:http://www.agner.org/optimize/instruction_tables.pdf

    【讨论】:

    • 这是废话,因为确实存在 8 位和 16 位 CPU。该链接仅比较不同的 PC。
    猜你喜欢
    • 2020-08-01
    • 1970-01-01
    • 2019-05-20
    • 1970-01-01
    • 2020-10-12
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    相关资源
    最近更新 更多