【问题标题】:Avoiding BigInteger class/large numbers in arithmetic在算术中避免 BigInteger 类/大数
【发布时间】:2015-03-25 06:12:23
【问题描述】:

我正在对字符串执行一些 mod 算术类型的操作,其中每个 char 都有一个特定的初始值(取决于它的 ascii)和字符串中的位置。这些数字变得非常大,因为它们的初始值为(ascii)*26^charPos。值得注意的是,数字字符只是将它们的值(0-9)加到总数中;

有没有办法避免使用 BigInt 类(因为我只对(intialVal)%(relatively small number)) 感兴趣,我想你可以使用通常的:

value += val;
  if(value >= mod)
   value = value % mod;

但这仅适用于整数的排序列表,也无法解决单个字符何时通过使用上述字符值公式生成 BigInt 的问题。我确信可以使用 mod 运算符完成一些事情。

顺便说一句; 如果 bigNum 超过 long(或 int,无论 foo 声明为)的大小,算法将无法正确计算,对吗?

int(or long) foo = BigNum(possibly bigger than long) % smallMod;

我意识到我可以声明几个 BigInteger 对象,然后将所有值添加到一个 totalValue 中,然后对总数执行最终的 mod 操作,但如果可能的话,我宁愿避免这种情况,因为 BigInteger 算术是我没有使用太多的东西(在这种情况下,这似乎是一种痛苦,通常是不必要的)。我知道会有很多方法,但我不介意听到一些不同的观点。提前致谢。

这是我想出的一些代码,只要没有打破长阈值,它就可以工作;

public static void main(String[] args) {

    String str = "st4ck0ver";

    char[] x = str.toCharArray();
    long value = 0;
    int mod = 87;

    for(int i = 0; i < x.length; i++) {

        long val;
        int charVal;
        int exp = x.length - (i+1);

        if((int)x[i] < 58) {
            charVal = (int)x[i] - 48;
            val = charVal;
        }
        else{
            charVal = (int)x[i]- 96;
            val = (long) (charVal * Math.pow(26, exp));
        }

        value += val;

        System.out.println("exp:" + exp + ",  char:" + x[i] + ", "
                + ",  charValue:" + charVal + " value:" + val + ",  curr total value:" + value);
    }
    value %= mod;
    System.out.println("Final value:" + value); 
}

编辑:回应大卫华莱士的回答:

对不起,我重读了你的解释,我明白你在做什么......你的回答正是我的意思。我只是在处理字符是数字的情况下遇到了麻烦,因为它只添加数值而不是将其乘以26^pos。我保留了数值的运行总计,以便将其添加到最终答案中(如果超过 mod 值,则再次对其进行修改),但我不知道如何将适当的功率增加一好。我可能遗漏了一些非常明显的东西。注释代码是我解决这个问题的一半尝试:

public static void main(String[] args) {
    //String str = "st4ck0ver";
    //String str = "hello";
    String str = "time2go";

    char[] x = str.toCharArray();
    int mod = 2004;

    int answer = 0;
    int power = 1;
    int numericalVal = 0;
    //int skipPower;

    for (int i = x.length - 1; i >=0; i--) {
        int charVal;

        if((int)x[i] < 58)  {
            charVal = (int)x[i] - 48;
            numericalVal += charVal;
            //skipPower++; //perhaps need to use something like this?
                //
        }       //      down
        else {  //   in here somewhere
            charVal = (int)x[i]- 96;

            answer += ( charVal * power);
            answer %= mod;
            power *= 26;
            power %= mod;
            //skipPower = 0; //reset skipPower in case it was used
        }
    }
    //answer += numericalVal;
    //if(answer + numericalVal >= mod)
    //  answer %= mod;

    System.out.println("Final value:" + answer);    
}

【问题讨论】:

  • 你的问题很不清楚!!!
  • 我同意您的问题不清楚。但是如果你想弄清楚如何对一个对于long 来说太大的整数执行% 操作,我建议你坚持使用BigInteger,除非smallMod 是2 的幂。和% 不定大小的整数很难自己实现,我很确定实现BigInteger 的人已经付出了很多努力和研究来开发最好的算法来完成这项工作。

标签: java


【解决方案1】:

如果您在某个模数中执行此操作,则遍历您的 String,跟踪您在该模数中所需值的运行总计,以及 26 的适当幂的值,也在该模数中.如您所说,如果模数非常小,那么 int 应该足以满足其中的每一个。

请注意,这里我假设您的String 仅包含小写字母。如果需要,请修复此问题。

int answer = 0;
int power = 1;

for (int i = 0; i < inputString.length(); i++) {
    int charValue = inputString.charAt(i) - 'a';
    answer += ( charValue * power );
    answer %= mod;
    power *= 26;
    power %= mod;
}

编辑

适应OP的编辑,这表明String必须以相反的顺序遍历,并且遇到数字时不考虑位值,代码应该如下。

int answer = 0;
int power = 1;

for (int i = inputString.length() - 1; i >=0; i--) {

    if(inputString.charAt( i ) < 58)  {
        int charValue  = inputString.charAt( i ) - 48;
        answer += charValue;
    }       
    else {  
        int charValue  = inputString.charAt( i ) - 96;
        answer += ( charValue * power );
    }

    answer %= mod;
    power *= 26;
    power %= mod;
}

【讨论】:

  • 感谢您的回复。当字符串中的一个字符的初始值(出现在长字符串中)超过 long 时,就会出现问题。 (我意识到我不需要数组,但我之前在执行与整数类似的操作并且没有更改它。)
  • char 的值怎么会超过long 的大小?
  • 我的意思是该特定字符根据其在字符串中的位置及其在字母表中的位置生成的值。值 = (posInAlpha)(26^posInString)。我无法修改值公式
  • 但是您在问题中说您将其全部添加到特定的小值模数中;在您的示例代码中,该模数为 87。除非该模数接近 int 的大小,否则我的方法将正常工作。如果您在所需的模数中有 26^posInString 的值,则 26^posInString 的 REAL 值无关紧要。
  • 我怀疑我的模数会超过 200。但我仍然不确定你的方法是如何工作的。你的方法正是我要问的,但我不太了解携带模数。最后一句“如果您在所需的模数中有 26^posInString 的值,则 26^posInString 的实际值无关紧要”很好,但我看不出您的代码是如何实现的。
【解决方案2】:

如果结果:

long longVal = new BigInteger(stringVal).mod(new BigInteger(modulus)).longValue();

太大而无法放入long 你会遇到以下行为,引用JDK 中的BigInteger#longValue 方法:

如果这个 BigInteger 太大而无法放入 long 中,则只返回低 64 位。请注意,此转换可能会丢失有关 BigInteger 值整体大小的信息,并返回带有相反符号的结果。

因此,如果您尝试从大于 longBigInteger 获得 long 值,您将无法获得准确的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 2019-05-29
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多