Optimization 什么';把一个整数除以3的最快方法是什么? intx=n/3;//

Optimization 什么';把一个整数除以3的最快方法是什么? intx=n/3;//,optimization,bit-manipulation,division,Optimization,Bit Manipulation,Division,我不知道它是否更快,但如果您想使用位运算符执行二进制除法,您可以使用如下所述的移位和减法: 将商设置为0 将除数和除数中最左边的数字对齐 重复: 如果除数上方的股息部分大于或等于除数: 然后从那部分股息中减去除数,然后 在商的右端插入1 否则将0与商的右端相连 将除数右移一位 直到股息小于除数: 商是正确的,被除数是余数 停止 如果你真的想看这篇文章,但它只有学术价值。。。这将是一个有趣的应用程序,实际上需要执行从这种技巧中受益的操作。这是最快的,因为编译器将根据输出处理器对其进行优

我不知道它是否更快,但如果您想使用位运算符执行二进制除法,您可以使用如下所述的移位和减法:

  • 将商设置为0
  • 将除数和除数中最左边的数字对齐
  • 重复:
    • 如果除数上方的股息部分大于或等于除数:
      • 然后从那部分股息中减去除数,然后
      • 在商的右端插入1
      • 否则将0与商的右端相连
    • 将除数右移一位
  • 直到股息小于除数:
  • 商是正确的,被除数是余数
  • 停止

如果你真的想看这篇文章,但它只有学术价值。。。这将是一个有趣的应用程序,实际上需要执行从这种技巧中受益的操作。

这是最快的,因为编译器将根据输出处理器对其进行优化

int x = n / 3;  // <-- make this faster

// for instance

int a = n * 3; // <-- normal integer multiplication

int b = (n << 1) + n; // <-- potentially faster multiplication
有关更有效地除以3的扩展讨论,请参见,重点是进行FPGA算术运算

同样相关的还有:

说“交给编译器”的人是对的,但我没有“名声”来修饰或评论他。我要求gcc为ix86编译int-test(int-a){returna/3;},然后反汇编输出。仅出于学术兴趣,它所做的是粗略地乘以0x555556,然后取64位结果的前32位。您可以通过以下方式向自己演示:

int a;
int b;

a = some value;
b = a / 3;
$ruby-e'put(60000*0x555556>>32)' 20000 $ruby-e'put(72*0x555556>>32)' 24 $
上的wikipedia页面很难阅读,但幸运的是编译器人员已经这样做了,因此您无需阅读。

取决于您的平台和C编译器,这是一个本机解决方案,就像使用

$ ruby -e 'puts(60000 * 0x55555556 >> 32)' 20000 $ ruby -e 'puts(72 * 0x55555556 >> 32)' 24 $ 它可以是快的,也可以是非常慢的(即使除法完全是在硬件中完成的,如果它是使用DIV指令完成的,这个指令也比现代CPU上的乘法慢3到4倍)。打开优化标志的非常好的C编译器可能会优化此操作,但如果您想确定,最好自己优化它

对于优化,具有已知大小的整数是很重要的。在C中,int没有已知的大小(它可能因平台和编译器而异!),所以最好使用C99固定大小的整数。下面的代码假设您想将一个无符号32位整数除以3,并且您的C编译器知道64位整数(注意:即使在32位CPU体系结构上,大多数C编译器也可以处理64位整数):

虽然这听起来很疯狂,但上面的方法确实被3除。这样做只需要一个64位乘法和一个移位(就像我说的,乘法可能比CPU上的除法快3到4倍)。在64位应用程序中,此代码比32位应用程序快得多(在32位应用程序中,两个64位数字相乘需要对32位值进行3次乘法和3次加法)-但是,它可能仍然比32位机器上的除法快

另一方面,如果您的编译器是一个非常好的编译器,并且知道如何通过常量优化整数除法(最新的GCC知道,我刚刚检查过),那么无论如何它都会生成上面的代码(如果您至少启用优化级别1,GCC将为“/3”创建此代码)。对于其他编译器。。。你不能依赖或期望它会使用这样的技巧,即使这种方法在互联网上到处都有很好的文档记录和提及

问题是它只适用于常量,而不适用于变量。您始终需要知道幻数(此处为0xaaaaab)和乘法后的正确运算(大多数情况下为移位和/或加法),两者都不同,取决于您要除以的数字,并且都需要太多的CPU时间来计算它们(这将比硬件除法慢)。然而,编译器很容易在编译时计算这些值(编译时多一秒或少一秒几乎不起作用)。

如果真的不想乘法或除法怎么办?这是我刚刚发明的近似值。它之所以有效是因为(x/3)=(x/4)+(x/12)。但是由于(x/12)=(x/4)/3,我们只需要重复这个过程,直到它足够好

static inline uint32_t divby3 (
    uint32_t divideMe
) {
    return (uint32_t)(((uint64_t)0xAAAAAAABULL * divideMe) >> 33);
}
#包括
void main()
{
int n=1000;
INTA,b;
a=n>>2;
b=(a>>2);
a+=b;
b=(b>>2);
a+=b;
b=(b>>2);
a+=b;
b=(b>>2);
a+=b;
printf(“a=%d\n”,a);
}
结果是330。使用b=((b+2)>>2)可以使其更精确;解释四舍五入

如果允许乘法,只需为(1/3)选择一个合适的近似值,除数为2的幂。例如,n*(1/3)~=n*43/128=(n*43)>>7


这项技术在

中最有用。如果您知道值的范围,有一种更快的方法,例如,如果您将一个有符号整数除以3,并且您知道要除以的值的范围是0到768,那么您可以将其乘以一个因子,然后将其向左移动2的幂,以将该因子除以3

例如

范围0->768

你可以使用10位移位,乘以1024,你想除以3,所以你的乘法器应该是1024/3=341

因此,您现在可以使用(x*341)>>10
(如果使用有符号整数,请确保移位是有符号移位),同时确保移位是实际移位而不是位滚动

这将有效地除以值3,并将在标准x86/x64 CPU上以大约1.6倍于自然除以3的速度运行

static inline uint32_t divby3 (
    uint32_t divideMe
) {
    return (uint32_t)(((uint64_t)0xAAAAAAABULL * divideMe) >> 33);
}
#include <stdio.h>

void main()
{
    int n = 1000;
    int a,b;
    a = n >> 2;
    b = (a >> 2);
    a += b;
    b = (b >> 2);
    a += b;
    b = (b >> 2);
    a += b;
    b = (b >> 2);
    a += b;
    printf("a=%d\n", a);
}
internal static List<int> Div3(int[] a)
{
  int remainder = 0;
  var res = new List<int>();
  for (int i = 0; i < a.Length; i++)
  {
    var val = remainder + a[i];
    var div = val/3;

    remainder = 10*(val%3);
    if (div > 9)
    {
      res.Add(div/10);
      res.Add(div%10);
    }
    else
      res.Add(div);
  }
  if (res[0] == 0) res.RemoveAt(0);
  return res;
}
uint8_t divideby3(uint8_t x)
{
  uint8_t answer =0;
  do
  {
    x>>=1;
    answer+=x;
    x=-x;
  }while(x);
  return answer;
}
uint8_t DivBy3LU(uint8_t u8Operand)
{
   uint8_t ai8Div3 = [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, ....];

   return ai8Div3[u8Operand];
}
uint64_t divBy3(uint64_t x)
{
    return x*12297829382473034411ULL;
}