以10为底的整数公式的补码的证明在哪里?

问题描述

因此,对于https://leetcode.com/problems/complement-of-base-10-integer/discuss/879910/Java-100-faster-solution-trick-to-find-2(digits-of-N)-1-greater-(11111)-and-subtract-N-from-it,谁能提供证明为什么2 ^(二进制数字的长度)-1给出完整的111 .... 1111二进制数字,全为1。如果有人可以重写此问题,请这样做。

解决方法

任何人都可以提供证明2 ^(二进制数字的长度)-1给出完整的111 .... 1111二进制数字的原因。

在(无符号)二进制表示法中,由N个“一位”数字组成的数字表示

precipitation = ["Sun","Rain","Sun","Rain"]

for i in precipitation:  
  if precipitation[i] == "Sun":
    precipitation[i] = 0
  else:
    precipitation[i] = 1

其中N> = 1。

所以我们实际上需要证明的是命题P(N)

2^0 + 2^1 + 2^2 + .... + 2^(N-1)

归纳证明

  1. 基本情况,N = 1。

    2^N - 1 = 2^0 + 2^1 + 2^2 + .... + 2^(N-1) where N >= 1.
    
  2. 鉴于P(N)为真,我们需要证明P(N + 1)也为真;即证明2^N - 1 = 2^1 - 1 = 2 - 1 = 1 = 2^0 Thus `P(1)` is proven

    假设P(N)为真;即P(N) => P(N+1) where N >= 1

    2^N - 1 = 2^0 + 2^1 + 2^2 + .... + 2^(N-1)

    但是

    (2^N - 1) * 2     = 2 * (2^0 + 2^1 + 2^2 + .... + 2^(N-1))
                      = 2 * 2^0 + 2 * 2^1 + 2 * 2^2 + 2 * 2^(N-1)
                      = 2^1 + 2^2 + 2^3 + ... + 2^N
    
    (2^N - 1) * 2 + 1 = 1   + (2^N - 1) * 2
                      = 2^0 + (2^N - 1) * 2
                      = 2^0 + 2^1 + 2^2 + 2^3 + ... + 2^N
    

    因此

    (2^N - 1) * 2 + 1 = 2 * 2^N - 2 * 1 + 1
                      = 2^(N+1) - 2 + 1
                      = 2^(N+1) - 1
    

    因此2^(N+1) - 1 = 2^0 + 2^1 + 2^2 + 2^3 + ... + 2^N 被证明

  3. 从步骤1开始,证明P(N) => P(N+1) where N >= 1

    从步骤2开始,证明P(1)

    因此,通过归纳,证明P(N) => P(N+1) where N >= 1

QED。

,

链接到的代码距离效率Math.pow(相对于基本位操作)非常昂贵,并且找出N的位边界的循环也不必要地无效。

为什么2 ^ 5-1总是以位为全1位的序列?

因为2^x是二进制数字系统的字面定义。如果更方便,我们来谈谈小数:

10^1是什么?现在是10。10^2是什么?它是100。10^3是1000,以此类推。从这些中的任何一个减去1,您将分别得到999999:最高数字(十进制为9,二进制为1)。因此,x^y-1,其中x是基数(十进制是'base 10',二进制是'base 2'),而y是任何正整数,将为您提供该基数的最高位数,重复y次,如果您在该基础上打印该号码。二进制中的2^18-1是18x 1。出于相同的原因,10^18-1会给您18倍的9

我们怎样才能更有效地做Math.pow(2,n)

相同的解释:因为2^x字面意义上的描述二进制数学,而计算机确实擅长于二进制数学,而按位运算则是二进制数学。全部为二进制:

1是十进制1。 10为十进制2。 101为十进制5。 1010为十进制10。

一般原理是,如果最后只推0,就等于将数字乘以2。回到十进制,如果我给你任何数字,比如说12493821345,写在一张纸上,然后我要求您将数字乘以10(请记住,十进制=以10为底,二进制=以2为底),您只需..在末尾添加零。与二进制相同:在末尾添加0等于乘以2。

因此,除了Math.pow(2,n)外,您还可以..加n个零。使用位移运算符执行的操作:“加5个零”与“将位5位置向左移动”相同。除了移位非常更有效。

因此,如果我想要2^10-1,执行此操作的有效方法是:

int n = 10;
int y = (1 << n) -1;
// y is now 1023,which is indeed 2^10 -1.

因此,应该是int pow = (1 << n) - 1;

您如何从N = 5快速到达111

这个问题的真正含义是:输入数字中最高1位的位置是什么。

二进制中的

5是101,所需的数字是2(因为在计算机中,计数是从0开始的,所以位置2是找到第3位的位置),如下所示:我们需要3个1位。换句话说,您的问题是:最高的1位是多少。 Java为此提供了一种方法:Integer.highestOneBit(5)。这不会返回最高1位的位置,而是返回仅将该位设置为1的那个数字。换句话说,5是101,而7是111。对于这两种情况,highestOneBit返回100(4)。将其左移1并减去1,然后将5和7都变成7,这就是您想要的。

请注意,这将执行更少的操作。还要注意,这些功能是 HIGHLY 调整的。从字面上看,相当多的Java性能工程师对这些问题进行了深入研究,以找到在大多数处理器上运行最快的实现,同时考虑到预测性流水线和CPU缓存的变化。他们倾向于正确解决这类问题,因此,您应该使用他们的东西。 Java是开放源代码,您可以根据需要检查实现。

您可以优化更多吗?

但是我们当然可以。

我真正需要做的就是首先翻转所有位,然后“翻转”前导零。给定一个5字节的字节:0000 0101,我们希望翻转所有位,但不翻转前导零:0000 0010 = 2,这是正确的答案。 Java有一个'flip all bits'运算符(NOT运算符~),因此我们所需要的只是'flip all bits'+'将所有那些前导位清零'。

这使我们能够:

public static int complement(int n) {
if (n == 0) return 1; // apparently an edge case; I'd say it's 0.
return ~n & ((Integer.highestOneBit(n) << 1) - 1);
}

无循环。 (hOB的impl也没有循环),没有昂贵的Math运算。所有基本位都在旋转。除了边套之外,还有一根内胆。

让我们测试一下!

complement(5) --> 101 -> 010 -> 2
complement(7) --> 111 -> 000 -> 0
complement(8) --> 1000 -> 0111 -> 7

似乎运作良好。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...