ADDITIONAL SYSTEM INFORMATION :
Tested with Oracle JDK 17.0.2. Operating system not relevant.
A DESCRIPTION OF THE PROBLEM :
The CompactNumberFormat class was introduced to make displaying large values in a compact manner consistent and easy across different implementations. For example, the value "5,213,222" being displayed as "5M". By default, the CompactNumberFormat supports rounding. For instance, "523,999" is formatted to 524K.
There appears to be an issue, though, when rounding causes the overall term to increase, say from thousand to million, or million to billion. For example, with rounding enabled, the values 999,999 and 1,000,000 should both format to "1M" using a short STYLE formatter. Instead, it prints as 1000K and 1M, respectively. Anyone displaying data coming from a CompactNumberFormat would see 1000K and quickly realize this is a display error. Note that this problem happens regardless of if the style SHORT or LONG is selected. In the case of LONG, the format would be "1000 thousand", which is even worse to see in a real application.
This behavior appears to be a bug related to rounding. If not a bug, then the CompactNumberFormat is not suitable for practical use. If a business displayed a monetary value as $1000K or "1000 thousand", instead of $1M, it would be very unprofessional. In other words, if this isn't a bug and the spec is correct, then the existence of this issue defeats the purpose of using CompactNumberFormat in the first place.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Sample code to reproduce the issue:
var nf1 = NumberFormat.getCompactNumberInstance(Locale.US,Style.SHORT);
System.out.println(nf1.format(999_999));
System.out.println(nf1.format(1_000_000));
System.out.println(nf1.format(1_999_999));
System.out.println(nf1.format(2_000_000));
var nf2 = NumberFormat.getCompactNumberInstance(Locale.US,Style.LONG);
System.out.println(nf2.format(999_999_999));
System.out.println(nf2.format(1_000_000_000));
System.out.println(nf2.format(1_999_999_999));
System.out.println(nf2.format(2_000_000_000));
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
1M
1M
2M
2M
1 billion
1 billion
2 billion
2 billion
ACTUAL -
1000K
1M
2M
2M
1000 million
1 billion
2 billion
2 billion
---------- BEGIN SOURCE ----------
import java.text.NumberFormat;
import java.text.NumberFormat.Style;
import java.util.Locale;
public class SampleCode {
public static void main(String[] arg) {
var nf1 = NumberFormat.getCompactNumberInstance(Locale.US,Style.SHORT);
System.out.println(nf1.format(999_999));
System.out.println(nf1.format(1_000_000));
System.out.println(nf1.format(1_999_999));
System.out.println(nf1.format(2_000_000));
var nf2 = NumberFormat.getCompactNumberInstance(Locale.US,Style.LONG);
System.out.println(nf2.format(999_999_999));
System.out.println(nf2.format(1_000_000_000));
System.out.println(nf2.format(1_999_999_999));
System.out.println(nf2.format(2_000_000_000));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The only work-around would be to disable rounding, or round the value before sending it to a CompactNumberFormat. Or don't use CompactNumberFormat at all because it is not useful.
FREQUENCY : always
Tested with Oracle JDK 17.0.2. Operating system not relevant.
A DESCRIPTION OF THE PROBLEM :
The CompactNumberFormat class was introduced to make displaying large values in a compact manner consistent and easy across different implementations. For example, the value "5,213,222" being displayed as "5M". By default, the CompactNumberFormat supports rounding. For instance, "523,999" is formatted to 524K.
There appears to be an issue, though, when rounding causes the overall term to increase, say from thousand to million, or million to billion. For example, with rounding enabled, the values 999,999 and 1,000,000 should both format to "1M" using a short STYLE formatter. Instead, it prints as 1000K and 1M, respectively. Anyone displaying data coming from a CompactNumberFormat would see 1000K and quickly realize this is a display error. Note that this problem happens regardless of if the style SHORT or LONG is selected. In the case of LONG, the format would be "1000 thousand", which is even worse to see in a real application.
This behavior appears to be a bug related to rounding. If not a bug, then the CompactNumberFormat is not suitable for practical use. If a business displayed a monetary value as $1000K or "1000 thousand", instead of $1M, it would be very unprofessional. In other words, if this isn't a bug and the spec is correct, then the existence of this issue defeats the purpose of using CompactNumberFormat in the first place.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Sample code to reproduce the issue:
var nf1 = NumberFormat.getCompactNumberInstance(Locale.US,Style.SHORT);
System.out.println(nf1.format(999_999));
System.out.println(nf1.format(1_000_000));
System.out.println(nf1.format(1_999_999));
System.out.println(nf1.format(2_000_000));
var nf2 = NumberFormat.getCompactNumberInstance(Locale.US,Style.LONG);
System.out.println(nf2.format(999_999_999));
System.out.println(nf2.format(1_000_000_000));
System.out.println(nf2.format(1_999_999_999));
System.out.println(nf2.format(2_000_000_000));
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
1M
1M
2M
2M
1 billion
1 billion
2 billion
2 billion
ACTUAL -
1000K
1M
2M
2M
1000 million
1 billion
2 billion
2 billion
---------- BEGIN SOURCE ----------
import java.text.NumberFormat;
import java.text.NumberFormat.Style;
import java.util.Locale;
public class SampleCode {
public static void main(String[] arg) {
var nf1 = NumberFormat.getCompactNumberInstance(Locale.US,Style.SHORT);
System.out.println(nf1.format(999_999));
System.out.println(nf1.format(1_000_000));
System.out.println(nf1.format(1_999_999));
System.out.println(nf1.format(2_000_000));
var nf2 = NumberFormat.getCompactNumberInstance(Locale.US,Style.LONG);
System.out.println(nf2.format(999_999_999));
System.out.println(nf2.format(1_000_000_000));
System.out.println(nf2.format(1_999_999_999));
System.out.println(nf2.format(2_000_000_000));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The only work-around would be to disable rounding, or round the value before sending it to a CompactNumberFormat. Or don't use CompactNumberFormat at all because it is not useful.
FREQUENCY : always