【问题标题】:Number of blocks to spit range of values over 64吐出值范围超过 64 的块数
【发布时间】:2020-07-13 00:44:35
【问题描述】:

我有以下代码:

long[] blocks = new long[(someClass.getMemberArray().length - 1) / 64 + 1];  

基本上someClass.getMemberArray() 可以返回一个比 64 大得多的数组,并且代码会尝试确定后续处理需要多少 len 64 块。
我对逻辑以及它是如何工作的感到困惑。在我看来,只是在做:

 long[] blocks = new long[(int) Math.ceil(someClass.getMemberArray().length / 64.0)];  

应该也可以工作,看起来更简单。
有人可以帮助我理解原始 sn-p 中的 -1+1 推理,它是如何工作的,以及 ceil 在某些情况下是否会失败?

【问题讨论】:

    标签: java arrays math integer integer-division


    【解决方案1】:

    我不明白为什么需要 -1,但 +1 可能会纠正除法结果向下舍入到最接近的非十进制值的情况(应该是,嗯,除结果不带小数的情况外的所有情况)

    【讨论】:

    • 如果 someClass.getMemberArray().length 是 64,那么如果没有减法,结果将是 2 而不是 1。所以计算是正确的。我对这背后的直觉有点困惑
    【解决方案2】:

    正如您正确评论的那样,需要 -1/+1 才能获得正确数量的块,包括仅部分填充的块。它有效地四舍五入。

    (但它有一些可能被认为是错误的东西:如果数组的长度为 0,这需要 0 个块,它返回 1。这是因为整数除法通常在大多数系统上截断,即向上舍入负数,所以 (0 - 1)/64 产生 0。但是,如果由于某些原因不允许零块,这可能是一个特性。但它确实需要注释。)

    第一行的原因是它只使用整数运算,在大多数计算机上应该只翻译一些基本和快速的机器指令。

    第二种解决方案涉及转换浮点算术和转换。传统上,大多数处理器上的浮点运算要慢得多,这可能是第一个解决方案的原因。但是,在具有集成浮点支持的现代 CPU 上,性能更多地取决于缓存线和流水线等其他因素。

    就个人而言,我不太喜欢这两种解决方案,因为它们的作用并不明显。所以我建议以下解决方案:

    int arrayLength = someClass.getMemberArray().length;
    int blockCount = ceilDiv(arrayLength, 64);
    long[] blocks = new long[blockCount];
    
    //...
    
    /**
     * Integer division, rounding up.
     * @return the quotient a/b, rounded up.
     */
    static int ceilDiv(int a, int b) {
        assert b >= 0 : b; // Doesn't work for negative divisor.
    
        // Divide.
        int quotient = a / b;
    
        // If a is not a multiple of b, round up.
        if (a % b != 0) {
            quotient++;
        }
    
        return quotient;
    }
    

    它很罗嗦,但至少很清楚应该发生什么,并且它提供了一个适用于所有整数(负除数除外)的通用解决方案。不幸的是,大多数语言都没有提供优雅的“整数除法”解决方案。

    【讨论】:

    • 我更喜欢你的解决方案,而不是你发布这个。我也想了解第一个的原意。我的意思是 -1/+1 背后的直觉是什么?我不明白。
    猜你喜欢
    • 2018-07-18
    • 1970-01-01
    • 2011-08-02
    • 2022-11-26
    • 1970-01-01
    • 1970-01-01
    • 2021-05-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多