BigDecimalのフォーマットのバグ
BigDecimalのフォーマットに問題があって成果物をリリースできなかった。以下はJDK5_U12〜U14だと落ちるがJDK6_U03だと正常動作する。
public class BigDecimalTest { public static void main(String[] args) { System.out.println("9.4 -> " + String.format("%.0f", new BigDecimal(9.4))); System.out.println("9.5 -> " + String.format("%.0f", new BigDecimal(9.5))); } }
9.4 -> 9 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException at java.lang.System.arraycopy(Native Method) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:519) at java.lang.StringBuilder.append(StringBuilder.java:190) at java.util.Formatter$FormatSpecifier$BigDecimalLayout.layout(Formatter.java:3690) at java.util.Formatter$FormatSpecifier$BigDecimalLayout.<init>(Formatter.java:3610) at java.util.Formatter$FormatSpecifier.print(Formatter.java:3545) at java.util.Formatter$FormatSpecifier.print(Formatter.java:3460) at java.util.Formatter$FormatSpecifier.printFloat(Formatter.java:2716) at java.util.Formatter$FormatSpecifier.print(Formatter.java:2664) at java.util.Formatter.format(Formatter.java:2430) at java.util.Formatter.format(Formatter.java:2364) at java.lang.String.format(String.java:2558) at test.BigDecimalTest.main(BigDecimalTest.java:85)
落ちる原因をおったところ、java.util.Formatter$FormatSpecifier$BigDecimalLayout.layout()に問題があることが分かった。1桁のバイト配列から2バイト読もうとして落ちていた。
JDK5
if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) { // count of padding zeros int pad = scale - coeff.length; if (pad >= 0) { // 0.xxx form mant.append("0."); dot = true; for (; pad > 0 ; pad--) mant.append('0'); mant.append(coeff); } else { // xx.xx form mant.append(coeff, 0, -pad); mant.append('.'); dot = true; mant.append(coeff, -pad, scale); } } else {
JDK6
if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) { // count of padding zeros int pad = scale - coeff.length; if (pad >= 0) { // 0.xxx form mant.append("0."); dot = true; for (; pad > 0 ; pad--) mant.append('0'); mant.append(coeff); } else { if (-pad < coeff.length) { // xx.xx form mant.append(coeff, 0, -pad); mant.append('.'); dot = true; mant.append(coeff, -pad, scale); } else { // xx form mant.append(coeff, 0, coeff.length); for (int i = 0; i < -scale; i++) mant.append('0'); this.scale = 0; } } } else {
JDK6で明らかにバグフィックスしている。JDK6で実行すると、「// xx form」のケースで処理されて正しい結果が得られる(しかし慌てたのかしらないけどインデントが汚くTABとスペースが先頭に混在してしまっている)。
なぜJDK5にも反映しないのさ。最近もU14出したばかりというのに。
→見つけた。http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6369500 レポートが1.5で起きているというのに、「mustangで対応したぜ!」…って、うぉい。
SUNの中の人、これ読んでたら諸々対応してくれないでしょうか。(ああ、また言いっ放しで終わる)