找出表示二进制正整数所需的位数?

joi*_*egs 28 java bits bit-manipulation

这可能是非常基本的,但为了节省我一小时左右的悲伤,任何人都可以告诉我如何计算出代表Java中给定正整数所需的位数?

例如,我得到小数11,(1011).我需要得到答案,4.

我想如果我能弄清楚如何将除最高位之外的所有位设置为0,然后>>>它,我会得到我的答案.但是......我做不到.

Var*_*han 31

嗯,答案很简单.如果你有一个int值:

int log2(int value) {
    return Integer.SIZE-Integer.numberOfLeadingZeros(value);
}
Run Code Online (Sandbox Code Playgroud)

Long存在同样的情况......

[编辑]如果剃须毫秒是一个问题,Integer.numberOfLeadingZeros(int)相当有效,但仍然进行15次操作......扩展合理的内存量(300字节,静态),你可以将其削减到1到8之间操作,取决于整数的范围.

  • 这是最快的解决方案.并且比接受的答案更容易遵循! (6认同)
  • 这可能是最快的解决方案,但从技术上讲,它并不是万无一失的。尝试用 value = 0 调用它,结果是:0。这是错误的,原因有两个:首先,从数学上讲,log2(0) 是未定义的。其次,在最初问题的上下文中:当您想要存储值为零的整数时,您将需要至少一位来执行此操作。 (2认同)
  • 根据 javadoc:请注意,此方法与以 2 为底的对数密切相关。对于所有正 int 值 x: `floor(log2(x)) = 31 - numberOfLeadingZeros(x)` `ceil(log2(x)) = 32 - 前导零数(x - 1)` (2认同)

i_a*_*orf 27

好吧,你可以算一下你离开前只有零次移动的次数:

int value = 11;
int count = 0;
while (value > 0) {
    count++;
    value = value >> 1;
}
Run Code Online (Sandbox Code Playgroud)

  • 不利于负面因素。尝试`while(值!= 0){++ count; 值>>> = 1; }`。>>>是逻辑(无符号扩展)右移运算符。 (2认同)

gno*_*ice 24

我的Java有点生疏,但与语言无关的答案(如果有"log2"函数和"floor"函数可用)将是:

numberOfBits = floor(log2(decimalNumber))+1
Run Code Online (Sandbox Code Playgroud)

假设"decimalNumber"大于0.如果为0,则只需要1位.

  • 我认为decimalNumber应该是decimalNumber + 1.log_2 256是8,而它需要9位来表示.log_2 0未定义,但它需要零位来表示. (2认同)

Tof*_*eer 13

Integer.toBinaryString(数字).长度();

好悲伤...为什么下来投票?

public class Main
{
    public static void main(final String[] argv)
    {
        System.out.println(Integer.toBinaryString(0).length());
        System.out.println(Integer.toBinaryString(1).length());
        System.out.println(Integer.toBinaryString(2).length());
        System.out.println(Integer.toBinaryString(3).length());
        System.out.println(Integer.toBinaryString(4).length());
        System.out.println(Integer.toBinaryString(5).length());
        System.out.println(Integer.toBinaryString(6).length());
        System.out.println(Integer.toBinaryString(7).length());
        System.out.println(Integer.toBinaryString(8).length());
        System.out.println(Integer.toBinaryString(9).length());
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

1
1
2
2
3
3
3
3
4
4
Run Code Online (Sandbox Code Playgroud)

这是对各种解决方案速度的简单测试:

public class Tester 
{
    public static void main(final String[] argv) 
    {
        final int size;
        final long totalA;
        final long totalB;
        final long totalC;
        final long totalD;

        size = 100000000;

        totalA = test(new A(), size);
        totalB = test(new B(), size);
        totalC = test(new C(), size);
        totalD = test(new D(), size);

        System.out.println();
        System.out.println("Total D = " + totalD + " ms");
        System.out.println("Total B = " + totalB + " ms");
        System.out.println("Total C = " + totalC + " ms");
        System.out.println("Total A = " + totalA + " ms");

        System.out.println();
        System.out.println("Total B = " + (totalB / totalD) + " times slower");
        System.out.println("Total C = " + (totalC / totalD) + " times slower");
        System.out.println("Total A = " + (totalA / totalD) + " times slower");
    }

    private static long test(final Testable tester, 
                             final int      size)
    {
        final long start;
        final long end;
        final long total;

        start = System.nanoTime();
        tester.test(size);
        end   = System.nanoTime();
        total = end - start;

        return (total / 1000000);
    }

    private static interface Testable
    {
        void test(int size);
    }

    private static class A
        implements Testable
    {
        @Override
        public void test(final int size)
        {
            int value;

            value = 0;

            for(int i = 1; i < size; i++)
            {
                value += Integer.toBinaryString(i).length();
            }

            System.out.println("value = " + value);
        }    
    }

    private static class B
        implements Testable
    {
        @Override
        public void test(final int size)
        {
            int total;

            total = 0;

            for(int i = 1; i < size; i++)
            {
                int value = i;
                int count = 0;

                while (value > 0) 
                {
                    count++;
                    value >>= 1;
                }

                total += count;
            }

            System.out.println("total = " + total);
        }    
    }

    private static class C
        implements Testable
    {
        @Override
        public void test(final int size)
        {
            int total;
            final double log2;

            total = 0;
            log2  = Math.log(2);

            for(int i = 1; i < size; i++)
            {
                final double logX;
                final double temp;

                logX   = Math.log(i);
                temp   = logX / log2;                
                total += (int)Math.floor(temp) + 1;
            }

            System.out.println("total = " + total);
        }    
    }

    private static class D
        implements Testable
    {
        @Override
        public void test(final int size)
        {
            int total;

            total = 0;

            for(int i = 1; i < size; i++)
            {
                total += 32-Integer.numberOfLeadingZeros(i);
            }

            System.out.println("total = " + total);
        }    
    }
}
Run Code Online (Sandbox Code Playgroud)

我机器上的输出是:

value = -1729185023
total = -1729185023
total = -1729185023
total = -1729185023

Total D = 118 ms
Total B = 1722 ms
Total C = 4462 ms
Total A = 5704 ms

Total B = 14 times slower
Total C = 37 times slower
Total A = 48 times slower
Run Code Online (Sandbox Code Playgroud)

对于那些抱怨速度的人... https://en.wikipedia.org/wiki/Program_optimization#Quotes.

编写程序首先可读,然后找出它慢的地方,然后加快速度.优化测试之前和之后的变化.如果更改不足以使代码不易读取的费用,请不要理会更改.

  • 并没有要求它快速:-) (3认同)
  • 这不是一个非常慢的原因 (2认同)

ojb*_*ass 11

取两个基于该数字的日志将报告存储它所需的位数.


AHe*_*lps 5

如果你试图避免循环而你关心速度,你可以使用这样的方法:

int value = ...;
int count = 0;
if( value < 0 ) { value = 0; count = 32; }
if( value >= 0x7FFF ) { value >>= 16; count += 16; }
if( value >= 0x7F ) { value >>= 8; count += 8; }
if( value >= 0x7 ) { value >>= 4; count += 4; }
if( value >= 0x3 ) { value >>= 2; count += 2; }
if( value >= 0x1 ) { value >>= 1; count += 1; }
Run Code Online (Sandbox Code Playgroud)

Java没有无符号整数,因此首先if(value <0)有点可疑.负数总是设置最重要的位,所以可以说需要完整的单词来表示它们.如果你在意的话,适应这种行为.

顺便提一下,要处理64位整数,请用这两个替换if(value <0)行:

if( value < 0 ) { value = 0; count = 64; }
if( value >= 0x7FFFFFFF ) { value >>= 32; count += 32; }
Run Code Online (Sandbox Code Playgroud)