круглое BigDecimal, чтобы соответствовать C ++ sprintf

Я перевожу приложение 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 ?)

ОБНОВИТЬ:
Макс Зум Спасибо. Ваш тест работает отлично.

Но в моем коде я получаю значения из БД, определенные как:

@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

1

Решение

Если вы хотите использовать собственное округление:

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);
}
5

Другие решения

Я удалил свое решение, так как оно было неверным. Но я приведу объяснение не столь очевидного поведения округления 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 заданные двойные значения точны, а режим округления также равен половине.

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

Эквивалент в Java:

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

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

автоматически округляется до десятых

если вы хотите изменить количество десятичных разрядов, которое оно округляет до:

"%.1f" раунды в одно место
"%.2f" туры в два места
"%.3f" туры в три места … и т. д.

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

заменяет:

sprintf(result,"%3.1lf",dArr[i]);
cout << result << endl;
-1
По вопросам рекламы [email protected]