Ошибка: при попытке отформатировать десятичный вывод в Java - PullRequest
0 голосов
/ 23 февраля 2020

Я пишу эту программу как задание для школы. Программа принимает от пользователя данные в форме «пол» и «возраст» и возвращает средний возраст всех мужчин и / или женщин.

Программа работала до тех пор, пока моя мама не провела ее бета-тестирование, и мы случайно обнаружили проблему. Если по какой-либо случайности пользователь введет число людей, для которых сумма их возрастов не делится на количество введенных людей, в результате будет получен ответ с 15 десятичными знаками. Например, если я введу 3 мужчин в возрасте 98, 1 и 1, программа делит 100 на 3, и я получаю вывод:

33.333333333333336.

Итак, я взял SO, чтобы найти решение этой проблемы, и нашел this , который я реализовал в своей программе, как показано ниже, чтобы он урезал ответ максимум до 3 десятичных знаков:

/*
This method takes two values. The first value is divided by the second value to get the average. Then it trims the
answer to output a maximum of 3 decimal places in cases where decimals run amok.
*/
public static double average (double a, double b){
    double d = a/b;
    DecimalFormat df = new DecimalFormat("#.###");
    return Double.parseDouble(df.format(d));

Я написал код внизу моей программы в своем собственном методе, который я вызываю в методе main в строках 76 и 77:

// Here we calculate the average age of all the people and put them into their respective variable.
    double yAverage = average(yAge, men);
    double xAverage = average(xAge, women);

Однако. Я получаю это сообщение об ошибке , когда я пытаюсь запустить программу, и я не понимаю сообщение об ошибке. Я попытался погуглить ошибку, но ничего не нашел. Пожалуйста, имейте в виду, что я новичок, и мне нужен настолько простой ответ, насколько кто-либо может дать мне. Заранее спасибо!

Ответы [ 2 ]

3 голосов
/ 23 февраля 2020

Проблема в том, что DecimalFormat учитывает ваши Locale настройки, форматируя число в соответствии с вашими языковыми настройками.

Например, в США Engli sh результат равен 33.333, но в Германии результат равен 33,333.

Однако Double.parseDouble(String s) жестко задан для анализа только форматирования US Engli sh.

Несколько вариантов чтобы исправить это:

  • Не округляйте значение. Рекомендуется

    Используйте DecimalFormat везде, где необходимо отобразить значение, но сохраняйте полную точность самого значения.

  • Принудительно DecimalFormat использовать символы форматирования US Engli sh.

    DecimalFormat df = new DecimalFormat("#.###", DecimalFormatSymbols.getInstance(Locale.US));
    
  • Используйте DecimalFormat для повторного анализа значения.

    DecimalFormat df = new DecimalFormat("#.###");
    try {
        return df.parse(df.format(d)).doubleValue();
    } catch (ParseException e) {
        throw new AssertionError(e.toString(), e);
    }
    
  • Не преобразовывать в / из строки в округление до 3 десятичных знаков.

    • Использовать Math.round(double a).

      return Math.round(d * 1000d) / 1000d;
      
    • Используйте BigDecimal (и придерживайтесь его) . Рекомендуется

      return BigDecimal.valueOf(d).setScale(3, RoundingMode.HALF_UP);
      
    • Использование BigDecimal (временно) .

      return BigDecimal.valueOf(d).setScale(3, RoundingMode.HALF_UP).doubleValue();
      
0 голосов
/ 23 февраля 2020

Попробуйте этот код

    public static double average(double a, double b) {
    double d = a / b;
    DecimalFormat df = new DecimalFormat(
            "#.###", 
            DecimalFormatSymbols.getInstance(Locale.ENGLISH)
    );
    return Double.parseDouble(df.format(d));
}

Вы используете форматирование с точкой в ​​качестве десятичного разделителя ("#. ###"). В зависимости от места, где вы запускаете вашу программу, среда выполнения Java использует разные настройки локализации, например, в Германии, где запятая используется в качестве десятичного разделителя. При использовании new DecimalFormat("#.###") языковой стандарт по умолчанию используется для интерпретации строки #.###, которая может работать в некоторых местах, но не работает в других. К счастью, есть другой конструктор для DecimalFormat, где вы можете указать, какие символы следует использовать. Используя DecimalFormatSymbols.getInstance(Locale.ENGLISH) в качестве второго параметра, вы указываете, что вы хотите использовать соглашения о форматировании Engli sh ("." В качестве десятичного разделителя, "," для тысяч).

...