C++ 用位移位法求奇数因子

C++ 用位移位法求奇数因子,c++,c++11,bit-shift,C++,C++11,Bit Shift,(此问题指的是共同力量问题) 我想知道是否有n(2≤ N≤ 10¹⁴)是否有奇数除数。使用C++11,我认为可以通过迭代每个奇数直到n,并使用%检查它是否可除来强制解决方案。例如: for(unsigned long long i=3;i<n;i+=2){ if(n%i==0) return true; //It has an odd divisor } return false; //n%j==0 was never true so it doesn't have an odd d

(此问题指的是共同力量问题) 我想知道是否有
n(2≤ N≤ 10¹⁴)
是否有奇数除数。使用C++11,我认为可以通过迭代每个奇数直到n,并使用
%
检查它是否可除来强制解决方案。例如:

for(unsigned long long i=3;i<n;i+=2){
   if(n%i==0) return true; //It has an odd divisor
}
return false; //n%j==0 was never true so it doesn't have an odd divisor
如果我没有弄错的话,最后一段代码是通过执行
n=n/2来检查最后一位
(n&1)
是否为奇数ⁿ
如何计算
n=n/2ⁿ
在解决问题时与检查每个奇数时具有相同的准确性?(我如何知道我没有“跳过”除数?)

这个更优化的解决方案有效地去除了2的任何幂,如果余数不是
1
的因子,那么它必须涉及其他因子

因为所有偶数因子都有
2
作为因子本身,所以这只是“煮沸”数字,直到有余数因子或
1

比如说:

0b11010 (26) -> 0b1101 (13)
0b11000 (24) -> 0b11 (3)
0b10000 (16) -> 0b1 (1)
也可以有几个主要因素,如:

0b1111110000 (1008) -> (63)

这是9×7,但是你可以把63看成是唯一的非偶数因子。

< P >为了理解这一点,你必须了解奇数和偶数的最右位是如何工作的。 基本上,任何奇数的第0位(最右边)都是1(记住从右边开始计数,即最右边的位是第0位,然后依次向左,即第1位、第2位等等),任何偶数的第0位都是0。
所以当你这么做的时候

int value = n & 1;
你在做的是,你在做n&1的“AND”,所以如果n是奇数,那么它的第0位将是1,例如,当你假设

int result = 5 & 1;
int result = 10 & 1;
30 = 10 * 3;
30 = 15 * 2;
30 = 5 * 6
10 = (1010) (2^3 * 1 + 2^2 * 0 + 2^1 * 1 + 2^0 * 0)
现在这个看起来像这样

(101) & (001)
1010 & 0001
因此,结果是1(因为1的所有其他位都是0,所以5&1的所有其他位的和的结果都是0,所以基本上还是1),但是如果n是偶数,那么它的第0位将是0,例如

int result = 5 & 1;
int result = 10 & 1;
30 = 10 * 3;
30 = 15 * 2;
30 = 5 * 6
10 = (1010) (2^3 * 1 + 2^2 * 0 + 2^1 * 1 + 2^0 * 0)
看起来像这样

(101) & (001)
1010 & 0001
现在,根据前面的示例,您可以看到偶数情况下的结果始终为0。 这就是为什么用这种方法检查一个数字是奇数还是偶数要快得多的原因,因为你没有使用所有的模和其他更高级的东西,你在这里做的是低级的东西

说到重点,我们必须检查一个数字是否包含奇数除数,让我们一步一步地看它
例如,一个数字就是它的除数的倍数

int result = 5 & 1;
int result = 10 & 1;
30 = 10 * 3;
30 = 15 * 2;
30 = 5 * 6
10 = (1010) (2^3 * 1 + 2^2 * 0 + 2^1 * 1 + 2^0 * 0)
但如果你仔细观察,你会发现它总是由相同的唯一素数组合而成,即

30 = 2 * 5 * 3;
30 = 3 * 5 * 2;
30 = 5 * 2 * 3;
现在让我们看看素数中的一个事实,我们看到2是唯一一个非奇数的素数。
如果我们遵循这个事实,我们可以确定,如果2乘以任何其他素数,那么结果数将始终是奇数(记住偶数*奇数=奇数)。 因此,如果我们想要一个没有任何奇因子的数,那么我们不希望它的乘法组合中有任何奇数素数,那么这个数应该是2乘法的组合,换句话说是2的幂。(我们可以忽略1的情况,因为在问题中不考虑作为输入)

所以如果我们只是检查一个数字是否是2的幂,我们的问题就解决了,即如果它是2的幂,那么它不包含任何奇数除数,否则它包含奇数除数。
现在我们如何确定一个数字是否是2的幂。
所以我们看到的任何数字都可以是二进制表示中不同位的组合
比如说

int result = 5 & 1;
int result = 10 & 1;
30 = 10 * 3;
30 = 15 * 2;
30 = 5 * 6
10 = (1010) (2^3 * 1 + 2^2 * 0 + 2^1 * 1 + 2^0 * 0)
如果任何数字是2的正幂,那么它的二进制表示中只有一个位为1,所有其他位都为0(对于2^0=1的情况,您可以看到,我们已经得到了x>1的约束,因此我们可以忽略1的大小写处理)

现在让我们看看这段代码

// it runs the while loop until all the right bits of first 1 bit is 0, that is it runs till we shift our rightmost 1 bit to 0th bit
while(!(n & 1)) { 
    n >>= 1; // if we are inside the loop, it means rightmost 1 is still not at 0th bit position, as the AND is done for 0th bit like I explained above, so doing this will right shift our rightmost 1, i.e if it was at 2nd position, it will now come at 1st position 
}

if(n == 1) {
   // if it is 1, it means only 1 bit is there in whole binary representation of the number which is at 0th position, it means it is a power of two(remember that this n is calculated based on sum of all the power of 2)
    return false; 
} else {
    return true;
}
!(n&1)
相当于
n&1==0
,并测试
n
是否为偶数,因为
n&1
对于奇数为1,对于偶数为0。
n>=1
将整数除以2。
(顺便说一句,几十年来,编译器已经完全能够对
n%2==0
n/=2
进行优化,并且在确定何时实际有益方面比人类要好得多。)

接下来是数学:

最小的奇数因子也是最小的奇数素数因子

如果
x
是奇数,我们知道它至少有一个奇数素数因子,因此至少有一个奇数除数

如果
x
为偶数,则可以将其写入
2*y
,其中
y
x/2

我们还知道,我们可以把
x
写成它的主要因子的乘积,
2*f0*f1*…*fn

因此,
y
f0*f1*…*fn
,并且
x/2
的奇数因子与
x
的奇数因子完全相同


重复使用
x/2
,直到达到1或大于2的奇数。

问题本身有一些歧义。
在所有情况下,问题的答案都很简单,因为奇数
1
是任何整数
n
的除数
因此,我怀疑其目的是寻找与
1
不同的奇数除数

根据算术基本定理,当所有素数的乘积上升到某个非负整数幂时,正整数可以以唯一的方式分解

例如,数字
600
被分解为
2*2*2*3*5*5
的乘积
唯一的偶数引物数是
2
,因此,在将
n
除以等于其素分解的
2
的所有因子后,只剩下奇数素因子

如果
n
有一些与
1
不同的奇数除数,则除以
n