使用Java如何在没有科学计数法的情况下打印双精度值?


221

我想在Java中打印双精度值而不使用指数形式。

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

它显示此E表示法:1.2345678E7

我希望它像这样打印它: 12345678

防止这种情况的最佳方法是什么?

Answers:


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.2345678E712345678
卑鄙的

1
@despicable:您可能一直在寻找答案的旧的,不完整的版本。尝试重新加载页面。应该有一个关于的段落%.0f
NPE

@despicable,您可以将dexp存储为一个int,以便您可以轻松地双向使用它
Justin

10
圆满结束
迷惑了

6
%.0f四舍五入数字。有没有办法只丢弃尾随零?
NurShomik

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

都具有相同的值。

Protip:如果您对为什么这些随机数出现在double值的某个阈值之外感到困惑,则此视频说明:computerphile 0.1+ 为什么0.2等于0.30000000000001

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


非常感谢您的回答,尤其是提示。.该视频解决了我的困惑。
AnujDeo

97

简而言之:

如果要消除尾随零和语言环境问题,则应使用:

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.printlnFloatingDecimal.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位数字时,您一定不能舍弃双精度数并失去精度。

您对docs.oracle.com/javase/7/docs/api/java/math/…new BigDecimal(myvalue).toPlainString()的描述有何看法,当给定不同类型的数字时,它的行为尚不明显,但确实消除了科学计数法。
德里克·马哈

4
new BigDecimal(0.00000021d).toPlainString()输出0.0000002100000000000000010850153241148685623329583904705941677093505859375,这不是您所期望的...
JBE 2015年

任何想法如何在斯卡拉使用您的答案?可能是适当进口的问题,但我是新来的。
jangorecki

BigDecimal.valueOf(0.00000021d).toPlainString()也可以正常工作(这是使用BigDecimal的String构造函数的原因)
marco

27

您可以尝试使用DecimalFormat。使用此类,您可以非常灵活地解析数字。
您可以精确设置要使用的模式。
以您的情况为例:

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

16

我有另一个涉及BigDecimal的toPlainString()的解决方案,但是这次使用String-constructor,这是javadoc中推荐的:

此构造函数与Float.toString和Double.toString返回的值兼容。通常,这是将float或double转换为BigDecimal的首选方法,因为它不会受到BigDecimal(double)构造函数的不可预测性的影响。

它的最短形式如下所示:

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

在Java 8之前的版本中,对于任何零值Doubles,其结果均为“ 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,这是最好的:简短,直接,可配置。
保罗

很好的解决方案,确实帮助我将双精度值转换为String并避免了科学计数法。谢谢!

为什么要d.doubleValue() == 0代替d == 0
阿列克谢·凡多

因为它避免了自动拆箱,在这种情况下,我会更喜欢这种做法,但是对此的看法当然可能有所不同。如果您使用的是Java 8(9可能相同),则可以完全省略这两行。
曼努埃尔

刚刚用Java 9尝试过,这两行也可以在9上省略。
曼努埃尔

8

只要您的电话号码是整数,此功能就可以使用:

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

如果double变量在小数点后具有精度,它将截断它。


4

我需要将一些double转换为货币值,发现大多数解决方案都可以,但对我而言不是。

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(大于或等于1000万)的任何值转换为科学计数法,即。sil符号

例如: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);
}

1

我认为每个人都有正确的想法,但并非所有答案都简单明了。我可以看到这是一段非常有用的代码。以下是将起作用的代码片段:

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

".8"此处设置要显示的小数位数。

我正在使用Eclipse,但没有问题。

希望这会有所帮助。我将不胜感激!


1

当我将其用作math.Eval()函数的字符串输入时,我的生产代码中也遇到了同样的问题,该函数需要一个类似“ x + 20/50”的字符串

我看了数百篇文章...最终由于速度我选择了这篇文章。而且由于Eval函数最终会将其转换回自己的数字格式,而math.Eval()不支持其他方法返回的结尾E-07,无论如何,超过5 dp的内容对于我的应用程序来说都是太多细节。

现在已在具有1,000多个用户的应用程序的生产代码中使用。

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”:“ SOME CORPORATION”}

像这样将值添加到节点会产生所需的结果:BigInteger.valueOf(Long.parseLong(value,10))

我不确定这是否是真正的话题,但是由于这个问题是我搜索解决方案时遇到的最热门问题,因此我认为我会在这里分享其他人的利益,就是那些搜索效果不佳的人。:D


-1

对于由a表示的整数值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);
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.