Как напечатать двойное значение без научной нотации с использованием Java?


223

Я хочу напечатать двойное значение в Java без показательной формы.

double dexp = 12345678;
System.out.println("dexp: "+dexp);

Это показывает , что это E обозначения: 1.2345678E7.

Я хочу напечатать это так: 12345678

Каков наилучший способ предотвратить это?

Ответы:


116

Вы можете использовать printf()с %f:

double dexp = 12345678;
System.out.printf("dexp: %f\n", dexp);

Это напечатает dexp: 12345678.000000. Если вы не хотите дробную часть, используйте

System.out.printf("dexp: %.0f\n", dexp);

При этом используется язык спецификатора формата, описанный в документации .

Формат по умолчанию toString(), используемый в исходном коде, изложен здесь .


1
но он показал, dexp: 12345681.000000что это неправильное значение. И на самом деле после этого я хочу отобразить его на своей веб-странице, где он отображается так. 1.2345678E7Есть ли в любом случае, через который я могу сохранить его в любом двойном, как 12345678и любым другим способом?
Гадкий

1
@despicable: Возможно, вы просматривали старую неполную версию ответа. Попробуйте перезагрузить страницу. Там должен быть абзац о %.0f.
NPE

@ Показательно, что вы можете хранить dexp как int, чтобы вы могли легко использовать его обоими способами
Джастин


6
%.0fокругляет число. Есть ли способ просто отбросить конечные нули?
НурШомик

239

Java предотвращает E запись в двойном:

Пять различных способов конвертировать двойное в нормальное число:

import java.math.BigDecimal;
import java.text.DecimalFormat;

public class Runner {
    public static void main(String[] args) {
        double myvalue = 0.00000021d;

        //Option 1 Print bare double.
        System.out.println(myvalue);

        //Option2, use decimalFormat.
        DecimalFormat df = new DecimalFormat("#");
        df.setMaximumFractionDigits(8);
        System.out.println(df.format(myvalue));

        //Option 3, use printf.
        System.out.printf("%.9f", myvalue);
        System.out.println();

        //Option 4, convert toBigDecimal and ask for toPlainString().
        System.out.print(new BigDecimal(myvalue).toPlainString());
        System.out.println();

        //Option 5, String.format 
        System.out.println(String.format("%.12f", myvalue));
    }
}

Эта программа печатает:

2.1E-7
.00000021
0.000000210
0.000000210000000000000001085015324114868562332958390470594167709350585
0.000000210000

Которые все имеют одинаковую ценность.

Подсказка: если вы не уверены, почему эти случайные цифры появляются за определенным пороговым значением в двойном значении, это видео объясняет: computerphile, почему 0.1+ 0.2равно 0.30000000000001?

http://youtube.com/watch?v=PZRI1IfStY0


Большое спасибо за ответ и особенно за подсказку. Это видео разрешило мою путаницу.
AnujDeo

98

Коротко:

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

double myValue = 0.00000021d;

DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(340); // 340 = DecimalFormat.DOUBLE_FRACTION_DIGITS

System.out.println(df.format(myValue)); // Output: 0.00000021

Объяснение:

Почему другие ответы меня не устраивают:

  • Double.toString()или System.out.printlnили FloatingDecimal.toJavaFormatStringиспользует научные записи, если double меньше 10 ^ -3 или больше или равно 10 ^ 7
  • Используя %f, десятичная точность по умолчанию равна 6, в противном случае вы можете жестко закодировать ее, но это приведет к добавлению дополнительных нулей, если у вас меньше десятичных знаков. Пример:

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); // Output: 0.000000210000
  • Используя setMaximumFractionDigits(0);или %.0fвы удаляете любую десятичную точность, которая подходит для целых / длинных, но не для двойной:

    double myValue = 0.00000021d;
    System.out.println(String.format("%.0f", myvalue)); // Output: 0
    DecimalFormat df = new DecimalFormat("0");
    System.out.println(df.format(myValue)); // Output: 0
  • Используя DecimalFormat, вы локально зависимы. Во французском языке десятичный разделитель - это запятая, а не точка:

    double myValue = 0.00000021d;
    DecimalFormat df = new DecimalFormat("0");
    df.setMaximumFractionDigits(340);
    System.out.println(df.format(myvalue)); // Output: 0,00000021

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

Зачем использовать 340 тогда для setMaximumFractionDigits?

Две причины:

  • setMaximumFractionDigitsпринимает целое число, но его реализация имеет максимально допустимые цифры, DecimalFormat.DOUBLE_FRACTION_DIGITSравные 340
  • Double.MIN_VALUE = 4.9E-324 таким образом, с 340 цифрами вы точно не округлите свой двойной и не потеряете точность.

Каково ваше мнение? new BigDecimal(myvalue).toPlainString()Из описания на docs.oracle.com/javase/7/docs/api/java/math/… ) не сразу очевидно, как оно ведет себя при использовании различных типов чисел, но оно устраняет научную нотацию ,
Дерек Махар

4
new BigDecimal(0.00000021d).toPlainString()вывод, 0.0000002100000000000000010850153241148685623329583904705941677093505859375который не то, что вы ожидаете ...
JBE

Любая идея, как использовать свой ответ в Scala? вероятно, дело в соответствующем импорте, но я новичок здесь.
jangorecki

BigDecimal.valueOf(0.00000021d).toPlainString()работает также (он использует String конструктор BigDecimal, поэтому)
marco

27

Вы можете попробовать это с DecimalFormat. С этим классом вы очень легко разбираете свои числа.
Вы можете точно установить шаблон, который вы хотите использовать.
В вашем случае, например:

double test = 12345678;
DecimalFormat df = new DecimalFormat("#");
df.setMaximumFractionDigits(0);
System.out.println(df.format(test)); //12345678

16

У меня есть другое решение, включающее в себя BigDecimal toPlainString (), но на этот раз с использованием String-конструктор, который рекомендуется в javadoc:

этот конструктор совместим со значениями, возвращаемыми Float.toString и Double.toString. Как правило, это предпочтительный способ преобразования числа с плавающей запятой или двойного в BigDecimal, поскольку он не страдает от непредсказуемости конструктора BigDecimal (double).

В кратчайшем виде это выглядит так:

return new BigDecimal(myDouble.toString()).stripTrailingZeros().toPlainString();

До Java 8 это приводит к значению «0.0» для любых двойных чисел с нулевым значением, поэтому вам необходимо добавить:

if (myDouble.doubleValue() == 0)
    return "0";

NaN и бесконечные значения должны быть проверены дополнительно.

Окончательный результат всех этих соображений:

public static String doubleToString(Double d) {
    if (d == null)
        return null;
    if (d.isNaN() || d.isInfinite())
        return d.toString();

    // Pre Java 8, a value of 0 would yield "0.0" below
    if (d.doubleValue() == 0)
        return "0";
    return new BigDecimal(d.toString()).stripTrailingZeros().toPlainString();
}

Это также может быть скопировано / вставлено, чтобы хорошо работать с Float.


2
Я читал бесчисленные схемы для преобразования двойного значения в строку, и это лучшее: короткое, простое, настраиваемое.
Пол

Отличное решение, действительно помогло мне преобразовать двойные значения в String и избежать научной нотации. Спасибо!
17

Почему d.doubleValue() == 0вместо d == 0?
Алексей Фандо

Потому что он избегает автоматической распаковки, что мне больше нравится в этой ситуации, но взгляды могут, конечно, отличаться от этого. Если вы на Java 8 (9, вероятно, будет то же самое), вы можете пропустить эти две строки в целом.
Мануэль

Только что попробовал с java 9, эти 2 строки также могут быть опущены на 9.
Мануэль

8

Это будет работать до тех пор, пока ваш номер является целым числом:

double dnexp = 12345678;
System.out.println("dexp: " + (long)dexp);

Если переменная типа double имеет точность после десятичной точки, она ее усекает.


4

Мне нужно было конвертировать некоторые двойные значения в валюты и я обнаружил, что большинство решений были в порядке, но не для меня.

В DecimalFormatконечном итоге это был путь для меня, поэтому вот что я сделал:

   public String foo(double value) //Got here 6.743240136E7 or something..
    {
        DecimalFormat formatter;

        if(value - (int)value > 0.0)
            formatter = new DecimalFormat("0.00"); // Here you can also deal with rounding if you wish..
        else
            formatter = new DecimalFormat("0");

        return formatter.format(value);
    }

Как видите, если число натуральное, я получаю, скажем, 20000000 вместо 2E7 (и т. Д.) - без десятичной точки.

И если это десятичное число, я получаю только две десятичные цифры.


4

Компилятор Java / Kotlin преобразует любое значение больше 9999999 (больше или равно 10 миллионам) в научную нотацию, т.е. Epsilion запись .

Например: 12345678 преобразуется в 1,2345678E7

Используйте этот код, чтобы избежать автоматического преобразования в научную нотацию:

fun setTotalSalesValue(String total) {
        var valueWithoutEpsilon = total.toBigDecimal()
        /* Set the converted value to your android text view using setText() function */
        salesTextView.setText( valueWithoutEpsilon.toPlainString() )
    }

3

Следующий код определяет, представлен ли указанный номер в научной записи. Если это так, то он представлен в обычном формате с максимумом «25» цифр.

 static String convertFromScientificNotation(double number) {
    // Check if in scientific notation
    if (String.valueOf(number).toLowerCase().contains("e")) {
        System.out.println("The scientific notation number'"
                + number
                + "' detected, it will be converted to normal representation with 25 maximum fraction digits.");
        NumberFormat formatter = new DecimalFormat();
        formatter.setMaximumFractionDigits(25);
        return formatter.format(number);
    } else
        return String.valueOf(number);
}

2

Я думаю, что у всех была правильная идея, но все ответы были не простыми. Я вижу, что это очень полезный кусок кода. Вот фрагмент того, что будет работать:

System.out.println(String.format("%.8f", EnterYourDoubleVariableHere));

Здесь ".8"вы указываете количество десятичных разрядов, которые вы хотели бы показать.

Я использую Eclipse, и это не сработало.

Надеюсь, это было полезно. Буду признателен за любые отзывы!


1

У меня была такая же проблема в моем производственном коде, когда я использовал его в качестве строкового ввода в функцию math.Eval (), которая принимает строку типа «x + 20/50»

Я просмотрел сотни статей ... В конце концов я пошел с этим из-за скорости. И поскольку функция Eval собиралась в конечном итоге преобразовать ее обратно в свой собственный числовой формат, и math.Eval () не поддерживал завершающий E-07, который возвращали другие методы, и что-либо более 5 dp было слишком много деталей для моего приложения в любом случае ,

Это теперь используется в производственном коде для приложения, которое имеет более 1000 пользователей ...

double value = 0.0002111d;
String s = Double.toString(((int)(value * 100000.0d))/100000.0d); // Round to 5 dp

s display as:  0.00021

1

Это может быть касательная .... но если вам нужно поместить числовое значение в виде целого числа (которое слишком велико, чтобы быть целым числом) в сериализаторе (JSON и т. Д.), То вам, вероятно, нужен "BigInterger"

Пример: значение является строкой - 7515904334

Мы должны представить его как число в сообщении Json: {"contact_phone": "800220-3333", "servicer_id": 7515904334, "servicer_name": "SOME CORPORATION"}

Мы не можем его распечатать или получим: {"contact_phone": "800220-3333", "servicer_id": "7515904334", "servicer_name": "НЕКОТОРАЯ КОРПОРАЦИЯ"}

Добавление значения к узлу таким образом приводит к желаемому результату: BigInteger.valueOf (Long.parseLong (value, 10))

Я не уверен, что это действительно по теме, но, так как этот вопрос был моим главным хитом, когда я искал свое решение, я думал, что поделюсь здесь для пользы других, лгите мне, кто плохо ищет. : D


-1

Для целочисленных значений, представленных как double, вы можете использовать этот код, который намного быстрее, чем другие решения.

public static String doubleToString(final double d) {
    // check for integer, also see https://stackoverflow.com/a/9898613/868941 and
    // https://github.com/google/guava/blob/master/guava/src/com/google/common/math/DoubleMath.java
    if (isMathematicalInteger(d)) {
        return Long.toString((long)d);
    } else {
        // or use any of the solutions provided by others
        return Double.toString(d);
    }
}

// Java 8+
public static boolean isMathematicalInteger(final double d) {
    return StrictMath.rint(d) == d && Double.isFinite(d);
}

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.