Java 不使用Math.BigInteger的高次幂模

Java 不使用Math.BigInteger的高次幂模,java,math,modulo,exponent,Java,Math,Modulo,Exponent,我必须将此公式转换为java代码: 如果我可以使用Math.BigInteger之类的库,这会容易得多,但不幸的是,我应该在没有它的情况下这样做。关于stackoverflow的一些类似问题建议编写一个自己的bignum库,但我不想这样做 现在,我的进展是这样的: int h(String s) { long value = 1; int mod = ht.length; for (int i=0; i < s.length()-1; i++) { h += s.

我必须将此公式转换为java代码:

如果我可以使用Math.BigInteger之类的库,这会容易得多,但不幸的是,我应该在没有它的情况下这样做。关于stackoverflow的一些类似问题建议编写一个自己的bignum库,但我不想这样做

现在,我的进展是这样的:

int h(String s) {
  long value = 1;
  int mod = ht.length;

  for (int i=0; i < s.length()-1; i++) {
     h += s.charAt(i) * Math.pow(256,i);
  }
  return (int) h % mod;
}
inth(字符串s){
长值=1;
int mod=ht.length;
对于(int i=0;i
我知道幂的值很快就会超出整数范围,所以我想写一个自己的方法来计算幂和值的模。我的数学知识还不足以知道什么时候使用模,以及如何简化事情


提前谢谢

基本上,您应该将
移动到方程的更深处,以在每一步保持较低的值。为此,您基本上可以使用模块规则:

  • (a+b)%n=(a%n+b%n)%n
  • (a*b)%n=(a%n*b%n)%n
首先将其移动到循环中:

h = (h + s.charAt(i) * Math.pow(256, i)) % mod;
然后将其移动到
pow
中:

h = (h + s.charAt(i) * Math.pow(256 % mod, i)) % mod;
最后,我会停止使用
pow
和一些自定义电源,您可以在每个步骤后进行修改,如

(((256%mod)*256%mod)*256%mod)
我想你正在快速查看:

让我们考虑这个简单的公式来解释它是如何工作的:

x=A^B%C
as
x=5^117%19

1.将B分解为2的幂
117=(2^0+2^2+2^4+2^5+2^6)
117=(1+4+16+32+64)


2.计算两次幂的mod C如果你从后面走,你根本不需要取任何幂。在每一步简单地乘以256将产生相同的效果(后面的值“累积”更多的乘法,将它们提高到所需的幂)。Eg(未测试)


还要注意,
ht.length
不应该是二的幂(因此不能跳过循环中的模约化,如果
ht.length
是二的幂,则可以跳过模约化),因为如果它是二的幂,则散列取决于(最多)前4个字符,这显然很糟糕。

我为你的
n
选择了一个大素数默认情况下,问问你的导师,但使用任何非素数都不是一个好主意。如果这是哈希表中的桶数,请确保该数字是素数。另外,在for循环的退出条件中,您不能
-1
,因为您缺少最后一个字符

private static int MAX_PRIME = 2147483647; //largest positive 32 signed int prime (also happens to be the largest positive 32 signed int)

public static int hash(String s) {
    return hash(s, MAX_PRIME);
}

public static int hash(String s, int primeN) {
    long h = 1;
    long m = 1;

    for (int i = 0; i < s.length(); i++) {
        h += s.charAt(i) * m;
        h %= primeN;
        m *= 256;
        m %= primeN;
    }

    return (int) h;
}

字符串的hashvalues
Math.BigInteger
不是外部库。它是JDK的一部分,比如
String
Math.pow
。有多种方法可以散列字符串,这个方法有名字吗?你从哪里得到这张照片的?@Leo:再说一遍:
biginger
不是一个额外的库。它是JDK的一部分。如果您有
Math.pow
,那么您就有
java.Math.biginger
。如果你出于某种原因不想使用它,也没关系,但是,它不是附加的,也不是外部的,等等。它是基本Java类集合的一部分。可能是重复的,谢谢你的回答,我也想到了这一点。我只是不确定什么时候修改,因为公式在总结了所有的幂后需要修改。我是否也必须修改
s.charAt(I)
?有时在数学课上,我想我学到了,
(a*b)mod n=((a mod n)*(b mod n))mod n
@Leo我只包括了两个关于规则的句子,“array”似乎是哈希表(
ht
)。如果
ht
的长度是一个素数,那么它可能是n的一个很好的选择。我想如果你选择
MAX_PRIME
=2^32,你可以简单地让整数溢出进行模运算。@Calculator如果
n
不是一个质数,例如2^32,超过第四个字符对最后的hashok没有影响,我想第一个函数中
m
的计算仍然有问题,由于现在
*=256
步骤可能会在应用模之前结束(如果
MAX_PRIME
>2^24)。谢谢@harold,注意,出于这个原因,我将它们升级为
long
s哦,对不起,我错过了
long
-没问题,那么,我没有在公式中发现
1+
5^117 mod 19 = ( 5^1 * 5^4 * 5^16 * 5^32 * 5^64) mod 19
5^117 mod 19 = ( 5^1 mod 19 * 5^4 mod 19 * 5^16 mod 19 * 5^32 mod 19 * 5^64 mod 19) mod 19
5^117 mod 19 = ( 5 * 17 * 16 * 9 * 5 ) mod 19
5^117 mod 19 = 61200 mod 19 = 1
5^117 mod 19 = 1
int h(String s) {
  int res = 0;
  int n = ht.length;

  for (int i = s.length() - 1; i >= 0; i--) {
     // using a long here to prevent premature wrapping
     long t = res * 256L + s.charAt(i);
     res = (int)(t % n);
  }
  return (res + 1) % n;
}
private static int MAX_PRIME = 2147483647; //largest positive 32 signed int prime (also happens to be the largest positive 32 signed int)

public static int hash(String s) {
    return hash(s, MAX_PRIME);
}

public static int hash(String s, int primeN) {
    long h = 1;
    long m = 1;

    for (int i = 0; i < s.length(); i++) {
        h += s.charAt(i) * m;
        h %= primeN;
        m *= 256;
        m %= primeN;
    }

    return (int) h;
}
public static int hashBigInt(String s) {
    return hashBigInt(s, MAX_PRIME);
}

public static int hashBigInt(String s, int primeN) {
    final BigInteger bi256 = BigInteger.valueOf(256);
    BigInteger h = BigInteger.ONE;
    BigInteger m = BigInteger.ONE;

    for (int i = 0; i < s.length(); i++) {
        h = h.add(BigInteger.valueOf(s.charAt(i)).multiply(m));
        m = m.multiply(bi256);
    }

    return h.mod(BigInteger.valueOf(primeN))
            .intValue();
}