Note

Enhancement 8374202: Simplify significand normalization in BigDecimal(double, MathContext) constructor

Simplified the normalization process of the significand for BigDecimal(double, MathContext).

Overview#

The BigDecimal(double, MathContext) constructor includes a process to normalize the significand of a double. Previously, there was a loop that right-shifted the significand by one bit and incremented the exponent by 1 while the significand remained even.

while ((significand & 1) == 0) { // i.e., significand is even
    significand >>= 1;
    exponent++;
}

This process counts the number of consecutive zero bits at the right end of the significand and shifts them all at once to achieve the same result (or so it seems). Using Long.numberOfTrailingZeros, I determined the number of trailing zeros, then shifted and added in one step to normalize.

int nTrailingZeros = Long.numberOfTrailingZeros(significand);
significand >>= nTrailingZeros;
exponent += nTrailingZeros;

This change maintains the behavior while eliminating the loop for a more concise process.

Discovered on 2026/03/18 in JBS#

I discovered this issue through JBS and confirmed the implementation of BigDecimal(double, MathContext). In the affected section, there was a loop that normalized as long as the lower bits of the significand were zero.

However, Java already has Long.numberOfTrailingZeros, which can be used directly for this purpose. Since the normalization process is completed before entering if significand is 0, we can determine and apply the number of trailing zeros here.

In the PR, I replaced the loop-based normalization with Long.numberOfTrailingZeros and modified only one file: BigDecimal.java.

Review Comments on 2026/03/19#

Mr. Raffaello Giulietti1 commented that a similar proposal was sent to core-libs-dev in December 2025, but it did not progress at the time.

Given that there had already been a similar proposal, I believe this change was well-founded. However, since existing proposals can sometimes fall through the cracks, I felt that turning small changes into PRs has its value.

Review on 2026/03/27#

Mr. Giulietti1 reviewed and approved my PR but asked to wait for 24 hours before integrating it.

Therefore, I did not integrate immediately and performed /integrate the following day.

Integrated on 2026/03/30#

Mr. Giulietti1 sponsored the change with /sponsor, which was then integrated into JDK as commit d58fb1e2.


Footnotes#

  1. 2 3