如何用Java计算整数中的log base 2? [英] How do you calculate log base 2 in Java for integers?

查看:179
本文介绍了如何用Java计算整数中的log base 2?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用以下函数计算整数的log base 2:

I use the following function to calculate log base 2 for integers:

public static int log2(int n){
    if(n <= 0) throw new IllegalArgumentException();
    return 31 - Integer.numberOfLeadingZeros(n);
}

它是否具有最佳性能?

有人知道为此目的准备好J2SE API函数吗?

Does someone know ready J2SE API function for that purpose?

UPD1 令我惊讶的是,出现浮点算术比整数算术更快。

UPD2 由于评论,我会进行更详细的调查。

UPD3 我的整数运算函数比Math.log(n)/Math.log(2)快10倍。

推荐答案

如果您正在考虑使用浮点来帮助整数算术,那么您必须要小心。

If you are thinking about using floating-point to help with integer arithmetics, you have to be careful.

我通常尽可能避免计算FP。

I usually try to avoid FP calculations whenever possible.

浮点运算并不准确。你永远不可能知道(int)(Math.log(65536)/Math.log(2))评估为什么。例如, Math.ceil(Math.log(1<<<< 29)/ Math.log(2))在我的电脑上是30,在数学上它应该是29我没有找到x的值,其中(int)(Math.log(x)/Math.log(2))失败(仅因为只有32 危险值),但这并不意味着它在任何PC上的工作方式都相同。

Floating-point operations are not exact. You can never know for sure what will (int)(Math.log(65536)/Math.log(2)) evaluate to. For example, Math.ceil(Math.log(1<<29) / Math.log(2)) is 30 on my PC where mathematically it should be exactly 29. I didn't find a value for x where (int)(Math.log(x)/Math.log(2)) fails (just because there are only 32 "dangerous" values), but it does not mean that it will work the same way on any PC.

这里通常的技巧是在舍入时使用epsilon。像(int)(Math.log(x)/Math.log(2)+ 1e-10)应该永远不会失败。选择这个epsilon并不是一项微不足道的任务。

The usual trick here is using "epsilon" when rounding. Like (int)(Math.log(x)/Math.log(2)+1e-10) should never fail. The choice of this "epsilon" is not a trivial task.

使用更一般的任务进行更多演示 - 尝试实现 int log(int x,int base)

More demonstration, using a more general task - trying to implement int log(int x, int base):

测试代码:

static int pow(int base, int power) {
    int result = 1;
    for (int i = 0; i < power; i++)
        result *= base;
    return result;
}

private static void test(int base, int pow) {
    int x = pow(base, pow);
    if (pow != log(x, base))
        System.out.println(String.format("error at %d^%d", base, pow));
    if(pow!=0 && (pow-1) != log(x-1, base))
        System.out.println(String.format("error at %d^%d-1", base, pow));
}

public static void main(String[] args) {
    for (int base = 2; base < 500; base++) {
        int maxPow = (int) (Math.log(Integer.MAX_VALUE) / Math.log(base));
        for (int pow = 0; pow <= maxPow; pow++) {
            test(base, pow);
        }
    }
}

如果我们使用最直接 - 向前执行对数,

If we use the most straight-forward implementation of logarithm,

static int log(int x, int base)
{
    return (int) (Math.log(x) / Math.log(base));
}

打印:

error at 3^5
error at 3^10
error at 3^13
error at 3^15
error at 3^17
error at 9^5
error at 10^3
error at 10^6
error at 10^9
error at 11^7
error at 12^7
...

为了完全摆脱错误我有添加介于1e-11和1e-14之间的epsilon。
你能在测试之前告诉过这个吗?
我绝对不能。

To completely get rid of errors I had to add epsilon which is between 1e-11 and 1e-14. Could you have told this before testing? I definitely could not.

这篇关于如何用Java计算整数中的log base 2?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆