如何更有效地区分大数的奇数和偶数?



如果已经有一些类似的问题,请通过评论告诉我。

当我们通常尝试区分奇数和偶数时,我们可以尝试以下代码, 在C++。

int main() {
int n=10;

for(n; n>0; n--){

if(n%2==0) std::cout<< "even" << 'n';
if(n%2==1) std::cout<< "odd" << 'n';      
}   
}

我敢肯定,超过 99% 的本科生,甚至是专业人士,都会使用条件作为"如果(n%2==0)......否则"来区分奇数和偶数。

但是,当数字范围变得足够大时,在我看来"如果(n%2==0)......否则"的方法可能效率很低。让我来解释一下原因。

int main() {
int n=100000;

for(n; n>0; n--){

if(n%2==0) std::cout<< "even" << 'n';
if(n%2==1) std::cout<< "odd" << 'n';      
}   
}

当整数"n"很小时,将每个正整数除以小于它并不是什么大问题。

但是,当它变大时,难道没有比将它们分开更有效的方法吗?

我们人类通常不会计算模 2 来知道"10^1000 + 1"是奇数还是偶数。 它与"10^1000 + 2"、"10^1000 + 3"等相同。我们可以通过查看整数的最后一位数字来知道答案。

我不是CS方面的专家,所以即使我不确定这些信息,我听说机器对二进制数比人类更友好。如果是这样,计算机难道不能通过查看输入的最后一位数字(无论它们是0还是1)来更快地区分奇数和偶数吗?

如果对此有一些直接的答案,我相信许多中级数值算法可以从答案中受益。期待有人的帮助。

谢谢。

50000000%2 和 5%2 的性能时间真的一样吗?

这是假设编译器"查看数字"并"知道"其值有多大。分裂的情况并非如此。编译器看到一个int并对该int执行一些操作。不同的值只是在该int中设置的不同位,这些位始终具有执行除法时需要考虑的相同字节数。

另一方面,%2是一个如此常见的操作,编译器确实"知道在哪里查找":最后一点。

请考虑以下两个函数:

bool is_odd1(int n) { return (n%2);} 
bool is_odd2(int n) { return (n&1);}

n是奇数时,两者都返回true

is_odd1使用定义为除法后的余数的%。但是,仅仅因为它是这样定义的并不意味着它必须像这样实现。编译器将发出根据定义生成结果的代码,并且该代码可以预期非常有效。

is_odd2只考虑最低的n位来检查它是否被设置。

启用优化后,gcc 会为两者生成完全相同的输出:

is_odd1(int):
mov     eax, edi
and     eax, 1
ret
is_odd2(int):
mov     eax, edi
and     eax, 1
ret

这两个函数都不做任何事情,只是检查是否设置了最低位n

现场演示。

结论:不要担心这种微优化。如果可能,它们在编译器中实现。而是编写代码以提高清晰度和可读性。

但是,不要大规模引入低效率。例如,如果您像这样编写代码,则无需依赖编译器优化:

for(; n>0; n-=2){
std::cout<< "even" << 'n';
std::cout<< "odd" << 'n';      
} 

不过,无论如何,这都不是一个很好的例子,因为将某些内容打印到控制台比检查是否设置了单个位要昂贵得多。

如果你看一个用十进制写的数字,你可以很快知道它是奇数还是偶数:

  • 如果它以 0、2、4、6 或 8 结尾,则它是偶数;
  • 如果它以 1、3、5、7 或 9 结尾,那么它是奇数。

计算机上的数字以二进制形式存储。二进制几乎与十进制相同,只是它使用以 2 为基数而不是以 10 为基数,因此仅使用位 0 或 1 而不是数字 0 到 9。

要检查用二进制写的数字是奇数还是偶数,请查看其最后一位:

  • 如果它以 0 结尾,则它是偶数;
  • 如果它以 1 结尾,那么它是奇数。

当您编写n % 2 == 0C++时,编译器会优化代码,并且根本不执行除法。相反,它只是查看最后一位n并检查它是 0 还是 1。

永远不要通过测试余数来测试奇偶校验(余数和除法是一个非常缓慢的操作)。通过使用位掩码(n & 1 == 0)测试最低有效位就足够了。

[顺便说一下,智能优化器将自动通过掩码代替a % 2测试。另一种选择是使用移位:a == (a >> 1) << 1检测到偶数。

如果你的数字是 BigNum,那么检查表示中低阶词的奇偶校验就足够了。

相关内容

  • 没有找到相关文章

最新更新