ฉันจะพิมพ์ค่าสองค่าโดยไม่มีเครื่องหมายทางวิทยาศาสตร์โดยใช้ 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

@despicable คุณสามารถจัดเก็บ dexp เป็น int เพื่อให้คุณสามารถใช้งานได้อย่างง่ายดายทั้งสองวิธี
Justin

10
ไอทีรอบปิดจำนวน
สับสน

6
%.0fปัดเศษตัวเลข มีวิธีการทิ้งศูนย์ต่อท้ายหรือไม่?
NurShomik

239

Java ป้องกันเครื่องหมาย E ในสองครั้ง:

วิธีที่แตกต่างกันห้าวิธีในการแปลง double เป็นหมายเลขปกติ:

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: ถ้าคุณกำลังสับสนว่าทำไมผู้ที่ตัวเลขสุ่มปรากฏเกินกว่าเกณฑ์ที่กำหนดในมูลค่าคู่วิดีโอนี้อธิบาย: 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ใช้สัญลักษณ์ทางวิทยาศาสตร์ถ้าสองครั้งมีค่าน้อยกว่า 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/ ...... ) มันไม่ชัดเจนในทันทีว่ามันจะทำงานอย่างไรเมื่อได้รับตัวเลขประเภทต่าง ๆ แต่จะกำจัดสัญกรณ์ทางวิทยาศาสตร์ .
Derek Mahar

4
new BigDecimal(0.00000021d).toPlainString()การส่งออก0.0000002100000000000000010850153241148685623329583904705941677093505859375ที่ไม่ได้เป็นสิ่งที่คุณคาดหวัง ...
JBE

ความคิดวิธีการใช้คำตอบของคุณในสกาล่า? อาจเป็นเรื่องของการนำเข้าที่เหมาะสม แต่ฉันใหม่ที่นี่
jangorecki

BigDecimal.valueOf(0.00000021d).toPlainString()ทำงานได้เป็นอย่างดี (ใช้ตัวสร้างสตริงของ BigDecimal นั่นเป็นสาเหตุ)
marco

27

DecimalFormatคุณสามารถลองกับ ด้วยคลาสนี้คุณจะสามารถแยกวิเคราะห์ตัวเลขได้อย่างยืดหยุ่น
คุณสามารถกำหนดรูปแบบที่คุณต้องการใช้
ในกรณีของคุณเช่น:

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

16

ฉันมีวิธีแก้ไขปัญหาอื่นที่เกี่ยวข้องกับ toPlainString () ของ BigDecimal แต่คราวนี้ใช้ String-constructor ซึ่งแนะนำใน javadoc:

ตัวสร้างนี้เข้ากันได้กับค่าที่ส่งกลับโดย Float.toString และ Double.toString นี่เป็นวิธีที่นิยมใช้ในการแปลง float หรือ double เป็น BigDecimal เนื่องจากไม่ได้รับความทุกข์ยากจากตัวสร้าง BigDecimal (double)

ดูเหมือนว่าในรูปแบบที่สั้นที่สุด:

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

ก่อน Java 8 จะให้ผลลัพธ์เป็น "0.0" สำหรับ Doubles ที่มีค่าเป็นศูนย์ใด ๆ ดังนั้นคุณจะต้องเพิ่ม:

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

นอกจากนี้ยังสามารถคัดลอก / วางเพื่อทำงานได้ดีกับโฟลท


2
ฉันได้อ่านโครงร่างที่นับไม่ถ้วนเพื่อแปลงค่าสองครั้งเป็นสตริงและนี่คือสิ่งที่ดีที่สุด: สั้นตรงไปตรงมากำหนดค่าได้
พอล

ทางออกที่ดีช่วยฉันในการแปลงค่าสองเท่าเป็น String และหลีกเลี่ยงสัญลักษณ์ทางวิทยาศาสตร์ ขอบคุณ!
ปิด

ทำไมd.doubleValue() == 0แทนd == 0?
Alexei Fando

เพราะมันหลีกเลี่ยงการแกะกล่องอัตโนมัติซึ่งฉันชอบดีกว่าในสถานการณ์นั้น แต่แน่นอนว่ามุมมองอาจแตกต่างกันในเรื่องนี้ หากคุณใช้งานจาวา 8 (9 อาจจะเหมือนกัน) คุณสามารถเว้น 2 บรรทัดเหล่านี้ไว้ด้วยกัน
มานูเอล

เพิ่งลองกับ java 9 ทั้งสองบรรทัดสามารถถูกปล่อยออกมาในวันที่ 9 เช่นกัน
มานูเอล

8

วิธีนี้จะใช้ได้ตราบใดที่หมายเลขของคุณเป็นจำนวนเต็ม:

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

หากตัวแปรสองตัวมีความแม่นยำหลังจากจุดทศนิยมมันจะตัดทอน


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 นั้นมีรายละเอียดมากเกินไปสำหรับแอปพลิเคชันของฉัน .

ตอนนี้ใช้ในรหัสการผลิตสำหรับแอปพลิเคชันที่มีผู้ใช้มากกว่า 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

นี่อาจจะเป็นแทนเจนต์ .... แต่ถ้าคุณต้องการใส่ค่าตัวเลขเป็นจำนวนเต็ม (ที่ใหญ่เกินไปที่จะเป็นจำนวนเต็ม) ใน serializer (JSON เป็นต้น) คุณอาจต้องการ "BigInterger"

ตัวอย่าง: value เป็นสตริง - 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);
}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.