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

Java 找出用二进制表示正整数所需的位数?,java,bit-manipulation,bits,Java,Bit Manipulation,Bits,这可能是非常基本的,但为了节省我一个小时左右的时间,谁能告诉我如何计算出用Java表示给定正整数所需的位数 e、 我得到一个小数点11,(1011)。我需要得到答案,4 我想如果我能想出如何将除最高有效位以外的所有位设置为0,然后>>>它,我就会得到我的答案。但是我做不到。好吧,你可以数一数你向右移动了多少次,然后你就只剩下零了: int value = 11; int count = 0; while (value > 0) { count++; value = valu

这可能是非常基本的,但为了节省我一个小时左右的时间,谁能告诉我如何计算出用Java表示给定正整数所需的位数

e、 我得到一个小数点11,(1011)。我需要得到答案,4


我想如果我能想出如何将除最高有效位以外的所有位设置为0,然后>>>它,我就会得到我的答案。但是我做不到。

好吧,你可以数一数你向右移动了多少次,然后你就只剩下零了:

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

我的Java有点生疏,但语言不可知的答案(如果有“log2”函数和“floor”函数可用)是:

numberOfBits = floor(log2(decimalNumber))+1
假设“小数”大于0。如果为0,则只需1位。

整数.toBinaryString(number).length()

好悲伤。。。为什么投票被否决

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());
    }
}
输出:

1
1
2
2
3
3
3
3
4
4
以下是各种解决方案速度的简单测试:

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);
        }    
    }
}
对于那些抱怨速度的人


首先编写可读的程序,然后找出它的速度慢的地方,然后使它更快。优化前后测试更改。如果更改的大小不足以降低代码的可读性,请不要为更改而烦恼。

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

答案很简单。如果您有一个int值:

int log2(int value) {
    return Integer.SIZE-Integer.numberOfLeadingZeros(value);
}
同样的情况长期存在

[编辑]
如果这里的剃须毫秒是个问题,Integer.numberOfLeadingZeros(int)相当有效,但仍执行15次操作。。。扩展一个合理的内存量(300字节,静态),您可以根据整数的范围将其减少到1到8个操作。

这是C语言,但我怀疑您可以相当容易地转换为Java:


如果您试图避免循环,并且您关心速度,您可以使用以下方法:

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; }
public static int getNumberOfBits(int N) {
    int bits = 0;
        while(Math.pow(2, bits) <= N){
           bits++;
       }
       return bits;
}
int值=。。。;
整数计数=0;
如果(值<0){value=0;count=32;}
如果(值>=0x7FFF){value>=16;计数+=16;}
如果(值>=0x7F){value>=8;计数+=8;}
如果(值>=0x7){value>=4;计数+=4;}
如果(值>=0x3){value>=2;计数+=2;}
如果(值>=0x1){value>=1;计数+=1;}
Java没有无符号整数,所以第一个if(值<0)有点可疑。负数总是设置最重要的位,因此可以说需要完整的字来表示负数。如果你在乎的话,就改变这种行为

顺便说一句,要处理64位整数,请将if(value<0)行替换为以下两行:

if( value < 0 ) { value = 0; count = 64; }
if( value >= 0x7FFFFFFF ) { value >>= 32; count += 32; }
if(value<0){value=0;count=64;}
如果(值>=0x7FFFFFFF){value>>=32;计数+=32;}

当然,这只适用于正整数。

对于非负值,最直接的答案可能是:

java.math.BigDecimal.valueOf(value).bitLength()

(对于负数,它将给出比绝对值小1的位长度,而不是从2的补码表示法中期望的无穷大。)

为了完整性,我想添加一些其他选项:

1
biginger.valueOf(i).bitLength()

不是很快。此外,
biginger.bitLength()
它有错误且不可靠(在Java7中已修复),因为当需要超过
Integer.MAX_值
位时(需要异常高的输入数!![例如1个左移
Integer.MAX_值
次,也称为
2^Integer.MAX_值
]))下一个
2^(2*Integer.MAX_VALUE)-2^Integer.MAX_VALUE
numbers的结果溢出并出现负数,这个数字太高了,你的头可能会爆炸。请注意,据估计,宇宙包含约10^80个原子;这个数字是
2^4G
G
如千兆,
1024*1024*1024

2

static int neededBits(int i)
{
    assert i > 0;
    int res;
    int sh;
    res = ((i > 0xFFFF) ? 1 : 0) << 4;
    i >>= res;
    sh = ((i > 0xFF) ? 1 : 0) << 3;
    i >>= sh;
    res |= sh;
    sh = ((i > 0xF) ? 1 : 0) << 2;
    i >>= sh;
    res |= sh;
    sh = ((i > 0x3) ? 1 : 0) << 1;
    i >>= sh;
    res |= sh;
    res |= (i >> 1);
    return res + 1;
}
静态int-needbits(int-i)
{
断言i>0;
国际关系;
int-sh;
res=((i>0xFFFF)?1:0)>=res;
sh=((i>0xFF)?1:0)>=sh;
res |=sh;
sh=((i>0xF)?1:0)>=sh;
res |=sh;
sh=((i>0x3)?1:0)>=sh;
res |=sh;
res |=(i>>1);
返回res+1;
}

一个非常快的解决方案,但仍然是旧的
32-整数的一半

像这样的东西怎么样:

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; }
public static int getNumberOfBits(int N) {
    int bits = 0;
        while(Math.pow(2, bits) <= N){
           bits++;
       }
       return bits;
}
publicstaticintgetnumberofbits(intn){
整数位=0;

虽然(Math.pow(2,bits)对2的指数进行二进制搜索比bit shift()解决方案快,如果数字很大(数千个十进制数字),这可能很有价值,但您知道最大可用位,并且不想生成表:

    int  minExpVal   = 0;
    int  maxExpVal   = 62;
    int  medExpVal   = maxExpVal >> 1;
    long medianValue = 0l;

    while (maxExpVal - minExpVal > 1) {
        medianValue = 1l << medExpVal;
        if (value > medianValue) {
            minExpVal = medExpVal;
        } else {
            maxExpVal = medExpVal;
        }
        medExpVal = (minExpVal + maxExpVal) >> 1;
    }

    return value == 1l << maxExpVal ?  maxExpVal  + 1 : maxExpVal;
基准:

Leading zeros time is: 2 ms
BinarySearch time is: 95 ms
BitShift time is: 135 ms
这个适合我

int numberOfBitsRequired(int n)
{
    return (int)Math.floor(Math.log(n)/Math.log(2)) + 1;
}
要同时包含负数,可以添加一个额外的位并使用它指定符号

public static int numberOfBitsRequiredSigned(int n)
{
    return (int)Math.floor(Math.log(Math.abs(n))/Math.log(2)) + 2;
}

如果不想修改原始值,也可以这样做

unsigned int value = 11;
unsigned int count = 0;
if(value > 0)
{
    for(int i=1;i<value;i*=2) // multiply by two => shift one to left
    {
        ++count;
    }
}
我们从右边的
i=1
开始。 然后我们继续乘以2,只要
i
。 同时,我们记录了有多少位向左移动

所以在这个例子中,只要
i
达到16,值就大于11,因此我们停止。然后我们将计算4位:
1*2*2*2=16(=2^4)


<强>小心符号数。当处理有正数或负数的带符号的数字时,你必须首先将负数乘以-1。另外,你必须考虑如何考虑符号位。

d'Oh!是的,这很简单。我期待着一些非常无聊的WiZARDR。y、 …感谢您的快速回复,我现在将使用它,但我很想看看是否有没有没有没有循环的方法之类的。好吧,您可以展开循环,因为它应该在32次迭代中进行限制(或者64次——不管Java如何工作)。在Java中int是32位,long是64位。好的,我给您发布了一个方法w
unsigned int value = 11;
unsigned int count = 0;
if(value > 0)
{
    for(int i=1;i<value;i*=2) // multiply by two => shift one to left
    {
        ++count;
    }
}
64 32 16  8  4  2  1
 0  0  0  1  0  1  1  -> binary representation of decimal number 'value' = 11 (=1+2+8)