舍入BigDecimal以匹配C ++ sprintf

时间:2015-01-21 23:27:15

标签: java c++ rounding bigdecimal

我正在将C ++应用程序迁移到Java。如何匹配sprintf的舍入行为?

int main() {
    char result[20];
    double dArr [6] = {5.05, 5.15, 5.25, 5.35, 5.45, 5.55};

    for(int i; i< 6; i++) {
        sprintf(result,"%3.1lf",dArr[i]);
        cout << result << endl;
    }
    return 0;
}


VALUE      C++ sprintf Rounding: 
---------  ----------------------------------------
5.05    -   5.0 (rounding: half_down or half_even?)
5.15    -   5.2 (rounding: half_up   or half_even?)
5.25    -   5.2 (rounding: half_down or half_even?)
5.35    -   5.3 (rounding: half_down or half_odd ?)
5.45    -   5.5 (rounding: half_up   or half_odd ?)
5.55    -   5.5 (rounding: half_down or half_odd ?)

更新
Max Zoom谢谢。你的测试工作完美。

但在我的代码中,我将DB的值定义为:

@Column(precision=3, scale=2) //Oracle: CLASSAVERAGE NUMBER(3,2)
private BigDecimal classaverage;

当我尝试将数字四舍五入到BigDecimal.ROUND_HALF_EVEN时:

System.out.println(getClassaverage() + " - " + getClassaverage().setScale(1,BigDecimal.ROUND_HALF_EVEN) );

我得到了值"5.55" rounded to "5.6".

在我修改了测试后,我明白为什么会发生这种情况:

@Test
public void main() {
   double [] dArr = {5.05, 5.15, 5.25, 5.35, 5.45, 5.55};
   for (double d : dArr) {
      System.out.println(new BigDecimal(d) + " - " + new BigDecimal(d).setScale(1, BigDecimal.ROUND_HALF_EVEN));
   }
} 

这就是我得到的:

5.04999999999999982236431605997495353221893310546875 - 5.0
5.1500000000000003552713678800500929355621337890625 - 5.2
5.25 - 5.2
5.3499999999999996447286321199499070644378662109375 - 5.3
5.45000000000000017763568394002504646778106689453125 - 5.5
5.54999999999999982236431605997495353221893310546875 - 5.5

当我将double[]替换为String[]时,您的测试会生成BigDecimal.ROUND_HALF_EVEN的预期值:

5.05 - 5.0
5.15 - 5.2
5.25 - 5.2
5.35 - 5.4
5.45 - 5.4
5.55 - 5.6

4 个答案:

答案 0 :(得分:5)

如果您想使用自己的四舍五入:

import java.math.BigDecimal;

public class BigDecimalFormat
{
   private static int ROUNDING_MODE = BigDecimal.ROUND_HALF_EVEN;
   private static int DECIMALS = 1;

  public static void main(String[] args) {
      double[] dArr = {5.05, 5.15, 5.25, 5.35, 5.45, 5.55};
      for (double d : dArr)
        System.out.println(rounded(new BigDecimal(d)));
  }   

   public static BigDecimal rounded(BigDecimal number){
    return number.setScale(DECIMALS, ROUNDING_MODE);
  }
}

您希望格式化货币编号:

public static String currencyFormat(BigDecimal n) {
  return NumberFormat.getCurrencyInstance().format(n);
}

答案 1 :(得分:2)

我删除了我的解决方案,因为它错了。但是我会解释C ++舍入的不那么明显的行为。

使用此C ++代码显示双打的内部值。

int main() {
    char result[20];
    double dArr [6] = {5.05, 5.15, 5.25, 5.35, 5.45, 5.55};
    for(int i = 0; i< 6; i++) {
        sprintf(result, "%3.16f  %3.1lf", dArr[i], dArr[i]);
        cout << result << endl;
    }
    return 0;
}

结果显示四舍五入总是一半。

5.0499999999999998  5.0
5.1500000000000004  5.2
5.2500000000000000  5.3
5.3499999999999996  5.3
5.4500000000000002  5.5
5.5499999999999998  5.5

我的初步修改建议

double[] dArr = {5.05, 5.15, 5.25, 5.35, 5.45, 5.55};
DecimalFormat df = new DecimalFormat("###.0");
for (double d : dArr) {
    System.out.printf("%.16f %s%n", d, df.format(d));
}

显示在Java中,给定的double值是精确的,舍入模式也是一半甚至。

5.0500000000000000 5.0
5.1500000000000000 5.2
5.2500000000000000 5.2
5.3500000000000000 5.4
5.4500000000000000 5.4
5.5500000000000000 5.6

答案 2 :(得分:0)

Java中的等价物:

System.out.printf("%3.1f", 5.05); // 5.1

答案 3 :(得分:-1)

System.out.printf("%.1f", insertFloatValueHere);

自动舍入到最接近的第十个

如果你想改变它舍入的小数位数:

"%.1f"轮到一个地方 "%.2f"轮到两个地方 "%.3f"轮到三个地方......等等。

System.out.printf("%.1f", dArr[i]);

取代:

sprintf(result,"%3.1lf",dArr[i]);
cout << result << endl;