On Tue, 9 Jul 2024 20:06:40 GMT, fabioromano1 <d...@openjdk.org> wrote:

>> I have implemented the Zimmermann's square root algorithm, available in 
>> works [here](https://inria.hal.science/inria-00072854/en/) and 
>> [here](https://www.researchgate.net/publication/220532560_A_proof_of_GMP_square_root).
>> 
>> The algorithm is proved to be asymptotically faster than the Newton's 
>> Method, even for small numbers. To get an idea of how much the Newton's 
>> Method is slow,  consult my article 
>> [here](https://arxiv.org/abs/2406.07751), in which I compare Newton's Method 
>> with a version of classical square root algorithm that I implemented. After 
>> implementing Zimmermann's algorithm, it turns out that it is faster than my 
>> algorithm even for small numbers.
>
> fabioromano1 has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Added comment on normalization in MutableBigInteger.sqrtRemZimmermann()

@fabioromano1 This is a first reading, comparing with the well documented 
algorithm in the Bertot, Margaud, Zimmermann paper.

src/java.base/share/classes/java/math/BigInteger.java line 2724:

> 2722:         if (this.signum < 0) {
> 2723:             throw new ArithmeticException("Negative BigInteger");
> 2724:         }

Please restore the original braces.

src/java.base/share/classes/java/math/MutableBigInteger.java line 46:

> 44:  * @author  Michael McCloskey
> 45:  * @author  Timothy Buktu
> 46:  * @author  Fabio Romano

In recent years we no longer add the @author tag. In fact, at some point we 
plan to remove them from the codebase.
Authorship is part of the git commits.

src/java.base/share/classes/java/math/MutableBigInteger.java line 128:

> 126:             intLen = 2;
> 127:             value[0] = hi;
> 128:             value[1] = (int) val;

Suggestion:

            value = new int[] {hi, (int) val}
            intLen = 2;

src/java.base/share/classes/java/math/MutableBigInteger.java line 1916:

> 1914:      * @throws ArithmeticException if the value returned by {@code 
> bitLength()}
> 1915:      * overflows the range of {@code int}.
> 1916:      * @return the integer square root of {@code this} and the 
> remainder if needed

To emphasize, make use of `<em>` tags, not `<b>`.

By convention, a blank line precedes `@return`, which precedes `@throws` (see 
some public API examples).

src/java.base/share/classes/java/math/MutableBigInteger.java line 1941:

> 1939: 
> 1940:             // Initial estimate is the square root of the unsigned long 
> value.
> 1941:             long s = (long) Math.sqrt(x > 0 ? x : x + 0x1p64);

As a matter of simplification, the above cases can be collapsed to just this 
one. I don't think there's a real need to optimize for 0, [1, 4), `int`.

Also, there should be a proof that the code below is correct, as there are many 
roundings involved.

Suggestion:

            long s = (long) Math.sqrt(x >= 0 ? x : x + 0x1p64);

src/java.base/share/classes/java/math/MutableBigInteger.java line 1967:

> 1965:         MutableBigInteger[] sqrtRem = x.sqrtRemZimmermann(x.intLen, 
> needRemainder);
> 1966: 
> 1967:         // Unnormalize

This unnormalization code, as well as the one in the next method, requires a 
full explanation, perhaps in abstract, mathematical terms, to help 
understanding.

src/java.base/share/classes/java/math/MutableBigInteger.java line 1997:

> 1995:         if (len == 2) { // Base case
> 1996:             long x = ((value[offset] & LONG_MASK) << 32) | 
> (value[offset + 1] & LONG_MASK);
> 1997:             long s = (long) Math.sqrt(x > 0 ? x : x + 0x1p64);

Again, this needs a proof that doing so is always correct.

Suggestion:

            long s = (long) Math.sqrt(x >= 0 ? x : x + 0x1p64);

src/java.base/share/classes/java/math/MutableBigInteger.java line 2020:

> 2018:          * The length is normalized to a mutiple of 4 because, in this 
> way,
> 2019:          * the input can be always split in blocks of words without 
> twiddling with bits.
> 2020:          */

What's substantially different here from the Bertot, Magaud, Zimmermann paper?
This is not explained in detail, so it is way harder to understand than the 
paper.

src/java.base/share/classes/java/math/MutableBigInteger.java line 2021:

> 2019:          * the input can be always split in blocks of words without 
> twiddling with bits.
> 2020:          */
> 2021:         final int limit = len;

The name `limit` reminds more an offset than a length.

src/java.base/share/classes/java/math/MutableBigInteger.java line 2023:

> 2021:         final int limit = len;
> 2022:         final int excessInts = (-len) & 3;
> 2023:         len += excessInts; // len must be a multiple of 4

A comment like "this computes `excessInts = 4 * ceil(len / 4) - len`" or 
similar is welcome.

src/java.base/share/classes/java/math/MutableBigInteger.java line 2030:

> 2028:         MutableBigInteger dividend = sr[1];
> 2029:         dividend.leftShift(blockBitLen);
> 2030:         dividend.add(getBlockZimmermann(1, len, limit, blockLen));

Maybe there's no need to use `add` here and just copying the block into the 
lower `blockLen` words is sufficient?

src/java.base/share/classes/java/math/MutableBigInteger.java line 2040:

> 2038:         sqrt.add(q);
> 2039: 
> 2040:         MutableBigInteger chunk = u;

I don't get the need for `chunk`. It should be possible to use `u` directly.
Is it for readability? Then maybe use a more "mathematical" name.

src/java.base/share/classes/java/math/MutableBigInteger.java line 2054:

> 2052: 
> 2053:                 rem.add(ONE);
> 2054:                 rem.subtract(twiceSqrt);

Shouldn't these be `rem + twiceSqrt - 1`?

src/java.base/share/classes/java/math/MutableBigInteger.java line 2063:

> 2061:         }
> 2062: 
> 2063:         // Unnormalize

Again, this unnormalization code requires a full explanation.

src/java.base/share/classes/java/math/MutableBigInteger.java line 2091:

> 2089:     }
> 2090: 
> 2091:     private MutableBigInteger getBlockZimmermann(int blockIndex, int 
> len, int limit, int blockLen) {

Please add a comment on what this method is supposed to do.

-------------

PR Review: https://git.openjdk.org/jdk/pull/19710#pullrequestreview-2174704290
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675834855
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675836169
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675837722
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675842182
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675847407
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675848405
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675849681
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675851990
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675852854
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675853104
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675854097
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675854623
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675855041
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675856204
PR Review Comment: https://git.openjdk.org/jdk/pull/19710#discussion_r1675856482

Reply via email to