代码之家  ›  专栏  ›  技术社区  ›  tijko

处理整数数组时出现意外结果

  •  0
  • tijko  · 技术社区  · 2 年前

    在经历并重新考虑一些 Java语言 我写了一段时间的代码 Project Euler .

    我遇到了整数溢出的问题,其中的答案太大,无法包含在类型中 int 。这是直截了当和直观的,但有些事情让我措手不及,我仍然不确定。不仅仅是包含大值的类型需要将其类型更改为 long 还有的阵列 int 的产品。

    问题的前提是:

    在这1000个数字的字符串中,找到13个相邻数字的最大乘积。

    然后,我们取一个长字符串(1000位数字),将其解析为整数,以找到乘积最大的连续13位数字。

    我的代码:

    import java.util.Arrays;
    
    
    public class Euler_8
    {
        private static String largeDigitStr = 
    "73167176531330624919225119674426574742355349194934"+
    "96983520312774506326239578318016984801869478851843"+
    "85861560789112949495459501737958331952853208805511"+
    "12540698747158523863050715693290963295227443043557"+
    "66896648950445244523161731856403098711121722383113"+
    "62229893423380308135336276614282806444486645238749"+
    "30358907296290491560440772390713810515859307960866"+
    "70172427121883998797908792274921901699720888093776"+
    "65727333001053367881220235421809751254540594752243"+
    "52584907711670556013604839586446706324415722155397"+
    "53697817977846174064955149290862569321978468622482"+
    "83972241375657056057490261407972968652414535100474"+
    "82166370484403199890008895243450658541227588666881"+
    "16427171479924442928230863465674813919123162824586"+
    "17866458359124566529476545682848912883142607690042"+
    "24219022671055626321111109370544217506941658960408"+
    "07198403850962455444362981230987879927244284909188"+
    "84580156166097919133875499200524063689912560717606"+
    "05886116467109405077541002256983155200055935729725"+
    "71636269561882670428252483600823257530420752963450";
    
        public static void main(String[] args)
        {
            long start = System.nanoTime();
            long greatestProduct = 0;
    
            for (int i = 0; i < largeDigitStr.length() - 12; i++) {
                String digitSubString = largeDigitStr.substring(i, i + 13);
                /* HERE is the line that caused the unexpected issue....
                 * Now if I change this to .mapToLong and store it as long[]
                 * No issues.... but the int[] will bring overflow
                 * changing the line to:
                 *   long[] digitArray = Arrays.stream(digitSubString.split("")
                 *                             .mapToLong(Integer::parseInt)
                 *                             .toArray();
                 * (along with the digitProduct but that was obvious)
                 * Fixes the overflow.
                 */
                int[] digitArray = Arrays.stream(digitSubString.split(""))
                                          .mapToInt(Integer::parseInt)
                                          .toArray();
                long digitProduct = Arrays.stream(digitArray)
                                          .reduce(1, (x, y) -> x * y);
                if (digitProduct > greatestProduct) { 
                    greatestProduct = digitProduct;
                }
            }
            long stop = System.nanoTime();
            System.out.println("Answer: " + greatestProduct);
            System.out.printf("Time: %.4f\n", ((float) stop - start) / 1_000_000_000);
        }
    }
    

    我本以为 .map 和 .reduce 将中间值存储在变量中 digitProduct 不 数组成员本身。我现在几乎是肯定的,从那以后 我有 要更改的数组的类型 减少 是在计算每个连续项时导致溢出,还是关闭?

    1 回复  |  直到 2 年前
        1
  •  5
  •   Sweeper    2 年前

    会预料到 .reduce 将中间值存储在变量中 digitProduct 而不是数组成员本身。

    减少 不将中间值存储在 digitalProduct ,但它也不将它们存储在“数组成员”中。

    问题是 Arrays.stream(digitArray) 创建 IntStream ,不是 LongStream 。有多个过载 Array.stream ( 1 , 2 ). 需要一个 int[] 返回 IntStream 而那个需要 long[] 返回一个 LongStream .

    IntStream.reduce 采取 IntBinaryOperator 和 LongStream.reduce 采取 LongBinaryOperator .

    它溢出的原因是您传递的lambda的返回类型为 int 在里面 .reduce(1, (x, y) -> x * y); ,lambda (x, y) -> x * y 预计需要两个 int s并返回 int 和 这 在哪里 * 溢出。它与数组的类型或将结果分配给的变量的类型无关 IntStream.reduce ,与一起工作 int s

    您不需要创建 长的 。您可以转换 IntStream 到 LongStream 打电话之前 reduce .

    Arrays.stream(digitArray)
        .asLongStream()
        .reduce(1, (x, y) -> x * y);