Làm cách nào để in một giá trị kép mà không cần ký hiệu khoa học bằng Java?


222

Tôi muốn in một giá trị kép trong Java mà không cần dạng hàm mũ.

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

Nó hiển thị ký hiệu E này : 1.2345678E7.

Tôi muốn nó in như thế này: 12345678

Cách tốt nhất để ngăn chặn điều này là gì?

Câu trả lời:


116

Bạn có thể sử dụng printf()với %f:

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

Điều này sẽ in dexp: 12345678.000000. Nếu bạn không muốn phần phân số, sử dụng

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

Điều này sử dụng ngôn ngữ định dạng định dạng được giải thích trong tài liệu .

toString()Định dạng mặc định được sử dụng trong mã gốc của bạn được đánh vần ở đây .


1
nhưng nó cho thấy dexp: 12345681.000000đó là giá trị sai. Và thực sự sau đó tôi muốn hiển thị nó trên trang web của mình nơi nó hiển thị như thế này 1.2345678E7. Dù sao tôi cũng có thể lưu trữ nó theo bất kỳ cách nào 12345678và bất kỳ cách nào khác?
Tuyệt vọng

1
@despossible: Bạn có thể đã xem xét phiên bản cũ, chưa hoàn chỉnh của câu trả lời. Hãy thử tải lại trang. Cần có một đoạn về %.0f.
NPE

@despossible bạn có thể lưu trữ dex dưới dạng int để bạn có thể dễ dàng sử dụng cả hai cách
Justin

10
VÒNG NÓ RA KHỎI SỐ
Nhầm lẫn

6
%.0flàm tròn số. Có cách nào để loại bỏ các số 0 không?
NurShomik

239

Java ngăn ký hiệu E thành hai lần:

Năm cách khác nhau để chuyển đổi gấp đôi thành số bình thường:

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

Chương trình này in:

2.1E-7
.00000021
0.000000210
0.000000210000000000000001085015324114868562332958390470594167709350585
0.000000210000

Đó là tất cả cùng một giá trị.

Protip: Nếu bạn bối rối về lý do tại sao những chữ số ngẫu nhiên đó xuất hiện vượt quá một ngưỡng nhất định trong giá trị kép, video này giải thích: computerphile tại sao 0.1+ 0.2bằng 0.30000000000001?

http://youtube.com/watch?v=PZRI1 IfStY0


Cảm ơn rất nhiều vì câu trả lời và đặc biệt là mẹo .. Video đó đã giải quyết được sự nhầm lẫn của tôi.
AnujDeo

97

Nói ngắn gọn:

Nếu bạn muốn thoát khỏi các vấn đề về số 0 và Locale, thì bạn nên sử dụng:

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

Giải trình:

Tại sao các câu trả lời khác không phù hợp với tôi:

  • Double.toString()hoặc System.out.printlnhoặc FloatingDecimal.toJavaFormatStringsử dụng các ký hiệu khoa học nếu đôi là ít hơn 10 ^ -3 hoặc lớn hơn hoặc bằng 10 ^ 7
  • Bằng cách sử dụng %f, độ chính xác thập phân mặc định là 6, nếu không bạn có thể mã hóa nó, nhưng nó sẽ dẫn đến các số không được thêm vào nếu bạn có số thập phân ít hơn. Thí dụ:

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); // Output: 0.000000210000
  • Bằng cách sử dụng setMaximumFractionDigits(0);hoặc %.0fbạn loại bỏ bất kỳ độ chính xác thập phân nào, điều này tốt cho số nguyên / độ dài, nhưng không phải là gấp đôi:

    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
  • Bằng cách sử dụng DecimalFormat, bạn phụ thuộc cục bộ. Trong ngôn ngữ Pháp, dấu tách thập phân là dấu phẩy, không phải là điểm:

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

    Sử dụng ngôn ngữ TIẾNG VIỆT đảm bảo bạn có được một điểm cho dấu tách thập phân, bất cứ nơi nào chương trình của bạn sẽ chạy.

Tại sao dùng 340 thì để setMaximumFractionDigits?

Hai lý do:

  • setMaximumFractionDigitschấp nhận một số nguyên, nhưng việc thực hiện nó có một chữ số tối đa được phép DecimalFormat.DOUBLE_FRACTION_DIGITSbằng 340
  • Double.MIN_VALUE = 4.9E-324 vì vậy với 340 chữ số, bạn chắc chắn không làm tròn số của mình và mất độ chính xác.

Ý kiến ​​của bạn về new BigDecimal(myvalue).toPlainString()Từ mô tả tại docs.oracle.com/javase/7/docs/api/java/math/ ,), không rõ ràng cách nó hoạt động khi đưa ra các loại số khác nhau, nhưng nó loại bỏ ký hiệu khoa học .
Derek Mahar

4
new BigDecimal(0.00000021d).toPlainString()đầu ra 0.0000002100000000000000010850153241148685623329583904705941677093505859375không phải là những gì bạn mong đợi ...
JBE

Bất kỳ ý tưởng làm thế nào để sử dụng câu trả lời của bạn trong scala? có lẽ là một vấn đề nhập khẩu thích hợp nhưng tôi mới ở đây.
jangorecki

BigDecimal.valueOf(0.00000021d).toPlainString()cũng hoạt động (nó sử dụng hàm tạo Chuỗi của BigDecimal là lý do tại sao)
marco

27

Bạn có thể thử nó với DecimalFormat. Với lớp học này, bạn rất linh hoạt trong việc phân tích số của mình.
Bạn có thể chính xác đặt mẫu bạn muốn sử dụng.
Trong trường hợp của bạn chẳng hạn:

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

16

Tôi đã có một giải pháp khác liên quan đến toDainString () của BigDecimal, nhưng lần này sử dụng hàm tạo chuỗi, được khuyến nghị trong javadoc:

hàm tạo này tương thích với các giá trị được trả về bởi Float.toString và Double.toString. Đây thường là cách ưa thích để chuyển đổi float hoặc double thành BigDecimal, vì nó không bị ảnh hưởng bởi tính không thể đoán trước của hàm tạo BigDecimal (double).

Nó trông như thế này ở dạng ngắn nhất của nó:

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

Trước Java 8, kết quả này là "0,0" cho bất kỳ Nhân đôi có giá trị 0 nào, vì vậy bạn sẽ cần thêm:

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

NaN và giá trị vô hạn phải được kiểm tra thêm.

Kết quả cuối cùng của tất cả những cân nhắc này:

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

Điều này cũng có thể được sao chép / dán để hoạt động độc đáo với Float.


2
Tôi đã đọc vô số lược đồ để chuyển đổi một giá trị kép thành Chuỗi và đây là cách tốt nhất: ngắn, đơn giản, có thể định cấu hình.
Paul

Giải pháp tuyệt vời, thực sự đã giúp tôi chuyển đổi giá trị kép thành Chuỗi và tránh ký hiệu khoa học. Cảm ơn!
pleft

Tại sao d.doubleValue() == 0thay vì d == 0?
Alexei Fando

Bởi vì nó tránh tự động mở hộp, điều mà tôi thích hơn trong tình huống đó, nhưng tất nhiên các quan điểm có thể khác nhau về điều này. Nếu bạn đang dùng java 8 (9 có thể sẽ giống nhau), bạn có thể bỏ hoàn toàn 2 dòng đó.
Manuel

Chỉ cần thử với java 9, 2 dòng này cũng có thể bị bỏ lại trên 9.
Manuel

8

Điều này sẽ hoạt động miễn là số của bạn là một số nguyên:

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

Nếu biến kép có độ chính xác sau dấu thập phân, nó sẽ cắt nó.


4

Tôi cần phải chuyển đổi một số giá trị gấp đôi thành tiền tệ và thấy rằng hầu hết các giải pháp đều ổn, nhưng đối với tôi thì không.

Các DecimalFormatcuối cùng là cách đối với tôi, vì vậy đây là những gì tôi đã thực hiện:

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

Như bạn có thể thấy, nếu số đó là tự nhiên tôi nhận được - giả sử - 20000000 thay vì 2E7 (v.v.) - không có bất kỳ dấu thập phân nào.

Và nếu đó là số thập phân, tôi chỉ nhận được hai chữ số thập phân.


4

Trình biên dịch Java / Kotlin chuyển đổi bất kỳ giá trị nào lớn hơn 9999999 (lớn hơn hoặc bằng 10 triệu) thành ký hiệu khoa học tức là. Ký hiệu Epsgroup .

Ví dụ: 12345678 được chuyển đổi thành 1.2345678E7

Sử dụng mã này để tránh chuyển đổi tự động sang ký hiệu khoa học:

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

Đoạn mã sau phát hiện nếu số được cung cấp được trình bày theo ký hiệu khoa học. Nếu vậy, nó được biểu diễn trong bản trình bày bình thường với tối đa '25' chữ số.

 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

Tôi nghĩ mọi người đều có ý kiến ​​đúng, nhưng tất cả các câu trả lời đều không đơn giản. Tôi có thể thấy đây là một đoạn mã rất hữu ích. Đây là một đoạn của những gì sẽ làm việc:

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

đó ".8"là nơi bạn đặt số lượng vị trí thập phân bạn muốn hiển thị.

Tôi đang sử dụng Eclipse và nó không hoạt động.

Hy vọng điều này là hữu ích. Tôi sẽ đánh giá cao bất kỳ thông tin phản hồi!


1

Tôi đã gặp vấn đề tương tự trong mã sản xuất của mình khi tôi đang sử dụng nó làm đầu vào chuỗi cho hàm math.Eval () có một chuỗi như "x + 20/50"

Tôi đã xem hàng trăm bài báo ... Cuối cùng tôi đã đi với nó vì tốc độ. Và bởi vì hàm Eval sẽ chuyển đổi nó trở lại định dạng số của chính nó và math.Eval () không hỗ trợ E-07 theo dõi mà các phương thức khác đã trả về và dù sao thì mọi thứ trên 5 dp đều quá chi tiết cho ứng dụng của tôi .

Điều này hiện được sử dụng trong mã sản xuất cho một ứng dụng có hơn 1.000 người dùng ...

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

s display as:  0.00021

1

Đây có thể là một tiếp tuyến .... nhưng nếu bạn cần đặt một giá trị số dưới dạng một số nguyên (quá lớn để trở thành một số nguyên) vào một bộ nối tiếp (JSON, v.v.) thì có lẽ bạn muốn "BigInterger"

Ví dụ: giá trị là một chuỗi - 7515904334

Chúng ta cần biểu thị nó dưới dạng số trong một tin nhắn Json: {"contact_phone": "800220-3333", "servicer_id": 7515904334, "servicer_name": "SOME CORPORATION"}

Chúng tôi không thể in nó hoặc chúng tôi sẽ nhận được điều này:

Thêm giá trị vào nút như thế này sẽ tạo ra kết quả mong muốn: BigInteger.valueOf (Long.parseLong (value, 10))

Tôi không chắc đây thực sự là chủ đề, nhưng vì câu hỏi này là câu hỏi hàng đầu của tôi khi tôi tìm kiếm giải pháp của mình, tôi nghĩ tôi sẽ chia sẻ ở đây vì lợi ích của người khác, nói dối tôi, người tìm kiếm kém. : D


-1

Đối với các giá trị nguyên được biểu thị bằng a double, bạn có thể sử dụng mã này, nhanh hơn nhiều so với các giải pháp khác.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.