例如,我有一个十进制数11(1011),我需要得到答案4。
我想知道如何将最高有效位以外的所有位设置为0,然后使用>>>运算符得到答案。但是,我不会做,请帮忙解答。
好的,答案非常简单。如果您有一个int值:
int log2(int value) {
return Integer.SIZE - Integer.numberOfLeadingZeros(value);
}
对于长整型也存在同样的方法...
[编辑] 如果毫秒级别的性能是一个问题,那么可以使用Integer.numberOfLeadingZeros(int)方法,它的效率相当高,但仍然需要执行15个操作... 如果扩展一定数量的内存(300字节,静态),则可以将此数字减少到1至8个操作,具体取决于您的整数范围。
你可以数一下在最终变为零之前,需要向右位移多少次:
int value = 11;
int count = 0;
while (value > 0) {
count++;
value = value >> 1;
}
while (value != 0) { ++count; value >>>= 1; }
。>>> 是逻辑(无符号扩展)右移操作符。 - Tom Hawtin - tackline>> 1
表示向下取整除以2(因此-1“除以2”仍为-1)。>>> 1
将数字视为正数(无符号)并除以2。 - Tom Hawtin - tackline我的Java有点生疏,但是如果有“log2”函数和“floor”函数(不考虑编程语言的限制),答案将会是:
numberOfBits = floor(log2(decimalNumber))+1
假设"decimalNumber"大于0。如果它是0,那么你只需要1位。
Integer.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);
}
}
}
我的机器上的输出是:
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
如果你对速度有抱怨......https://en.wikipedia.org/wiki/Program_optimization#Quotes。
首先编写易于阅读的程序,然后查找其慢的部分并使其更快。 在优化之前和之后测试更改。 如果改变量不够大,以至于降低代码可读性的代价不值得,就不要费心去进行改变。
BigInteger.valueOf(i).bitLength()
(这有点慢:在我的机器上,大约比您的 D 慢 5 或 6 倍) - Unai ViviBigInteger.bitLength()
在Java 6中存在缺陷且不可靠。http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=c134915207cae78f258c98a958f3?bug_id=6910473 - Unai Vivi对该数字取以2为底的对数,可以得到存储该数字所需的位数。
int(log2(n)) + 1
。 - pronebird如果您想避免循环并且关心速度,可以使用以下方法:
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; }
Java没有无符号整数,因此第一个if(value < 0)有些可疑。负数总是设置最高位,因此需要完整的字来表示它们。如果您在意,可以调整该行为。
顺便说一句,要处理64位整数,请将if(value < 0)行替换为以下两行:
if( value < 0 ) { value = 0; count = 64; }
if( value >= 0x7FFFFFFF ) { value >>= 32; count += 32; }
java.math.BigDecimal.valueOf(value).bitLength()
System.out.println(BigInteger.valueOf(-1).bitLength());
输出的是0,而不是1。 - Unai ViviIllegalStateException
而不是执行一些奇怪的操作可能会更好。 - Tom Hawtin - tackline这个对我有效!
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;
}
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;
return Long.SIZE - Long.numberOfLeadingZeros(value);
基准测试:
Leading zeros time is: 2 ms
BinarySearch time is: 95 ms
BitShift time is: 135 ms
为了完整起见,我想添加一些其他的选择:
1 BigInteger.valueOf(i).bitLength()
速度不是很快。此外,BigInteger.bitLength()
存在错误和不可靠(在Java7中已修复),因为当需要超过Integer.MAX_VALUE
位时(需要非常高的输入数字![例如左移Integer.MAX_VALUE
次的1,即2^Integer.MAX_VALUE
]), 结果会溢出,并且负数会出现在接下来的2^(2*Integer.MAX_VALUE)-2^Integer.MAX_VALUE
个数字中,这个数字非常大,足以让你的头爆炸。请注意,宇宙中估计有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;
}
32 - Integer.numberOfLeadingZeros(i);
慢一半。
floor(log2(x)) = 31 - numberOfLeadingZeros(x)
ceil(log2(x)) = 32 - numberOfLeadingZeros(x - 1)
- mike