วิธีการปัดเศษทศนิยมเป็นทศนิยมใน Java


1259

สิ่งที่ฉันต้องการคือวิธีการแปลง double เป็น string ซึ่งปัดโดยใช้ half-up method เช่นถ้าทศนิยมที่จะปัดเศษเป็น 5 มันจะปัดเศษเป็นตัวเลขถัดไปเสมอ นี่เป็นวิธีมาตรฐานในการปัดเศษที่คนส่วนใหญ่คาดหวังในสถานการณ์ส่วนใหญ่

ฉันต้องการให้แสดงเฉพาะตัวเลขที่สำคัญเท่านั้น - นั่นคือไม่ควรมีเลขศูนย์ต่อท้าย

ฉันรู้วิธีหนึ่งในการทำเช่นนี้คือการใช้String.formatวิธีการ:

String.format("%.5g%n", 0.912385);

ผลตอบแทน:

0.91239

อันไหนดี แต่มันจะแสดงตัวเลขที่มีทศนิยม 5 ตำแหน่งเสมอแม้ว่ามันจะไม่สำคัญ:

String.format("%.5g%n", 0.912300);

ผลตอบแทน:

0.91230

วิธีอื่นคือใช้DecimalFormatter:

DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);

ผลตอบแทน:

0.91238

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

0.912385 -> 0.91239
0.912300 -> 0.9123

วิธีที่ดีที่สุดในการบรรลุสิ่งนี้ใน Java คืออะไร?

คำตอบ:


751

ใช้setRoundingModeตั้งค่าRoundingModeอย่างชัดเจนเพื่อจัดการกับปัญหาของคุณในรอบครึ่งจากนั้นใช้รูปแบบการจัดรูปแบบสำหรับผลลัพธ์ที่คุณต้องการ

ตัวอย่าง:

DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.CEILING);
for (Number n : Arrays.asList(12, 123.12345, 0.23, 0.1, 2341234.212431324)) {
    Double d = n.doubleValue();
    System.out.println(df.format(d));
}

ให้ผลลัพธ์:

12
123.1235
0.23
0.1
2341234.2125

แก้ไข : คำตอบเดิมไม่ได้อยู่ที่ความถูกต้องของค่าสองครั้ง ไม่เป็นไรถ้าคุณไม่สนใจมากไม่ว่าจะเป็นการปัดขึ้นหรือลง แต่ถ้าคุณต้องการการปัดเศษที่แม่นยำคุณต้องคำนึงถึงความแม่นยำของค่าที่คาดไว้ ค่าจุดลอยตัวมีการแสดงไบนารีภายใน นั่นหมายความว่าค่าเช่น 2.7735 ไม่ได้มีค่าที่แน่นอนภายใน มันสามารถใหญ่กว่าหรือเล็กกว่าเล็กน้อยได้ หากค่าภายในมีขนาดเล็กลงเล็กน้อยจะไม่ปัดขึ้นเป็น 2.7740 ในการแก้ไขสถานการณ์ดังกล่าวคุณจะต้องตระหนักถึงความถูกต้องของค่าที่คุณทำงานด้วยและเพิ่มหรือลบค่านั้นก่อนที่จะปัดเศษ ตัวอย่างเช่นเมื่อคุณรู้ว่าค่าของคุณมีความถูกต้องสูงถึง 6 หลักจากนั้นเมื่อต้องการปัดเศษค่าครึ่งทางให้เพิ่มความแม่นยำนั้นให้กับค่า:

Double d = n.doubleValue() + 1e-6;

หากต้องการปัดเศษให้ลบความแม่นยำออก


9
นี่อาจเป็นทางออกที่ดีที่สุดที่นำเสนอจนถึงขณะนี้ เหตุผลที่ฉันไม่เห็นสิ่งอำนวยความสะดวกนี้เมื่อฉันดูคลาส DecimalFormat ครั้งแรกนั่นคือมันถูกนำมาใช้ใน Java 1.6 เท่านั้น น่าเสียดายที่ฉันถูก จำกัด ให้ใช้ 1.5 แต่มันจะมีประโยชน์ที่จะรู้ในอนาคต
Alex Spurling

1
ฉันพยายามนี้ด้วย: ปัดเศษ"#.##" -> ... (ตัวอย่างมาจากความคิดเห็นถึงคำตอบของ @ asterite) HALF_UP256.335f"256.33"
bigstones

6
โปรดระวังเนื่องจาก DecimalFormat ขึ้นอยู่กับการกำหนดค่าปัจจุบันของคุณคุณอาจไม่ได้จุดเป็นตัวคั่น ฉันชอบคำตอบของดาวเคราะห์น้อยด้านล่างโดยส่วนตัว
Gomino

1
โปรดทราบว่าคุณไม่ควรคาดหวังว่า DecimalFormat จะปลอดภัยต่อเธรด ตามเอกสารของ Java : รูปแบบทศนิยมมักไม่ได้รับการซิงโครไนซ์ ขอแนะนำให้สร้างอินสแตนซ์รูปแบบแยกต่างหากสำหรับแต่ละเธรด หากหลายเธรดเข้าถึงรูปแบบพร้อมกันจะต้องซิงโครไนซ์ภายนอก
CGK

1
ฉันจะทำอย่างไรจึงจะได้การปัดเศษที่เหมาะสมดังนั้นจะไม่ปัดเศษ 0.0004 ถึง 0.001

471

สมมติว่าvalueเป็นdoubleคุณสามารถทำ:

(double)Math.round(value * 100000d) / 100000d

นั่นคือเพื่อความแม่นยำ 5 หลัก จำนวนศูนย์แสดงจำนวนทศนิยม


71
UPDATE: ฉันเพิ่งยืนยันว่าการทำเช่นนี้เป็นวิธีที่เร็วกว่าการใช้ DecimalFormat ฉันวนลูปโดยใช้ DecimalFormat 200 ครั้งและวิธีนี้ DecimalFormat ใช้เวลา 14 มิลลิวินาทีในการทำ 200 ลูปวิธีนี้ใช้เวลาน้อยกว่า 1 มิลลิวินาที อย่างที่ฉันสงสัยว่ามันเร็วกว่า หากคุณได้รับเงินตามรอบนาฬิกานี่คือสิ่งที่คุณควรทำ ฉันประหลาดใจที่ Chris Cudmore จะพูดในสิ่งที่เขาพูดด้วยความซื่อสัตย์ การจัดสรรวัตถุมักจะแพงกว่าการคัดเลือกแบบดั้งเดิมและใช้วิธีการแบบคงที่ (Math.round () ซึ่งตรงข้ามกับ decimalFormat.format ())
Andi Jay

99
เทคนิคนี้ล้มเหลวในกว่า 90% ของกรณี -1
user207421

25
อันที่จริงสิ่งนี้ล้มเหลว: Math.round(0.1 * Math.pow(10,20))/Math.pow(10,20) == 0.09223372036854775.
Robert Tupelo-Schneck

54
ระวังให้มากเมื่อใช้วิธีนี้ (หรือการปัดเศษของคะแนนลอย) มันล้มเหลวสำหรับบางสิ่งที่ง่ายเหมือน 265.335 ผลกลางของ 265.335 * 100 (ความแม่นยำ 2 หลัก) คือ 26533.499999999996 หมายความว่ามันถูกปัดเศษเป็น 265.33 มีเพียงปัญหาโดยธรรมชาติเมื่อแปลงจากตัวเลขทศนิยมเป็นตัวเลขทศนิยมจริง ดูคำตอบของ EJP ที่นี่ที่stackoverflow.com/a/12684082/144578
Sebastiaan van den Broek

6
@SebastiaanvandenBroek: ว้าวฉันไม่เคยรู้ว่ามันเป็นเรื่องง่ายที่จะได้รับคำตอบที่ผิด อย่างไรก็ตามหากมีการทำงานร่วมกับตัวเลขที่ไม่ใช่แน่นอนหนึ่งต้องยอมรับว่าค่าใด ๆไม่ได้เป็นที่แน่นอน 265.335จริงๆหมายถึง265.335 += toleranceที่ความอดทนขึ้นอยู่กับการทำงานก่อนหน้าและช่วงของค่าอินพุต เราไม่ทราบคุณค่าที่แท้จริงและแน่นอน ที่ค่าของขอบคำตอบอย่างใดอย่างหนึ่งอาจถูกต้อง หากเราต้องการความแน่นอนเราไม่ควรทำงานเป็นสองเท่า failที่นี่ไม่ได้ในการแปลงกลับไปเป็นสองเท่า มันอยู่ใน OP คิดว่าเขาสามารถพึ่งพาเข้ามา265.335ว่าเป็นอย่างนั้น
ToolmakerSteve

191
new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP);

BigDecimalคุณจะได้รับ ที่จะได้รับสตริงออกจากมันเพียงแค่เรียกว่าBigDecimal's toStringวิธีการหรือtoPlainStringวิธีการสำหรับ Java 5+ สำหรับรูปแบบของสตริงธรรมดา

โปรแกรมตัวอย่าง:

package trials;
import java.math.BigDecimal;

public class Trials {

    public static void main(String[] args) {
        int yourScale = 10;
        System.out.println(BigDecimal.valueOf(0.42344534534553453453-0.42324534524553453453).setScale(yourScale, BigDecimal.ROUND_HALF_UP));
    }

38
นั่นคือทางออกที่ฉันต้องการ ยิ่งสั้นลง: BigDecimal.valueOf (doubleVar) .setScale (yourScaleHere, BigDecimal.ROUND_HALF_UP); BigDecimal.valueOf (double val) จริง ๆ แล้วเรียก Double.toString () ใต้ฮูด;)
Etienne Neveu

4
ดี ไม่ตัดมุมและการใช้งานnew BigDecimal(doubleVar)ที่คุณสามารถใช้เป็นประเด็นที่มีการปัดเศษของจุดลอย
Edd

8
@Edd, น่าสนใจ, ปัญหาการปัดเศษเกิดขึ้นในกรณีที่ SebastiaanvandenBroek กล่าวถึงในความคิดเห็นต่อคำตอบของดาวเคราะห์น้อย double val = 265.335;, BigDecimal.valueOf(val).setScale(decimals, BigDecimal.ROUND_HALF_UP).toPlainString();=> 265.34, แต่(new BigDecimal(val)).setScale(decimals, BigDecimal.ROUND_HALF_UP).toPlainString();=> 265.33.
ToolmakerSteve

7
@ToolmakerSteve นั่นเป็นเพราะการใช้ BigDecimal ใหม่ที่มี double จะใช้ค่า double โดยตรงและพยายามที่จะใช้ BigDecimal ในขณะที่เมื่อใช้ BigDecimal.valueOf หรือแบบฟอร์ม tostring จะวิเคราะห์สตริงก่อน .
MetroidFan2002

116

คุณยังสามารถใช้

DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);

เพื่อให้แน่ใจว่าคุณมี 0 ต่อท้าย


25
ฉันเชื่อว่าหนึ่งในเป้าหมายของคำถามคือ " ไม่ควรมีเลขศูนย์ใด ๆ "
กล่องอาหารกลางวัน

7
สำหรับคำถามนี้ผู้ปฏิบัติการไม่ต้องการเป็นศูนย์ แต่นี่คือสิ่งที่ฉันต้องการ หากคุณมีรายการตัวเลขที่มีทศนิยม 3 ตำแหน่งคุณต้องการให้ทุกคนมีตัวเลขเหมือนกันแม้ว่าจะเป็น 0
Tom Kincaid

คุณลืมระบุRoundingMode.
IgorGanapolsky

1
@IgorGanapolsky ตามค่าเริ่มต้นการDecimal modeใช้งานRoundingMode.HALF_EVEN.
EndermanAPM

87

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

ฉันกำลังโพสต์รหัสต่อไปนี้เป็นตัวอย่างที่ตอบกลับไปยังคำตอบทั้งหมดในหัวข้อนี้และแน่นอนทั่ว StackOverflow (และที่อื่น ๆ ) ที่แนะนำการคูณตามด้วยการตัดทอนตามด้วยการหาร มีหน้าที่สนับสนุนผู้สนับสนุนของเทคนิคนี้เพื่ออธิบายว่าทำไมรหัสต่อไปนี้ก่อให้เกิดผลลัพธ์ที่ไม่ถูกต้องในกว่า 92% ของกรณี

public class RoundingCounterExample
{

    static float roundOff(float x, int position)
    {
        float a = x;
        double temp = Math.pow(10.0, position);
        a *= temp;
        a = Math.round(a);
        return (a / (float)temp);
    }

    public static void main(String[] args)
    {
        float a = roundOff(0.0009434f,3);
        System.out.println("a="+a+" (a % .001)="+(a % 0.001));
        int count = 0, errors = 0;
        for (double x = 0.0; x < 1; x += 0.0001)
        {
            count++;
            double d = x;
            int scale = 2;
            double factor = Math.pow(10, scale);
            d = Math.round(d * factor) / factor;
            if ((d % 0.01) != 0.0)
            {
                System.out.println(d + " " + (d % 0.01));
                errors++;
            }
        }
        System.out.println(count + " trials " + errors + " errors");
    }
}

ผลลัพธ์ของโปรแกรมนี้:

10001 trials 9251 errors

แก้ไข:เพื่อที่จะแสดงความคิดเห็นบางส่วนด้านล่างฉันได้ลดโมดูลัสส่วนหนึ่งของลูปการทดสอบโดยใช้BigDecimalและnew MathContext(16)สำหรับการดำเนินการโมดูลัสดังต่อไปนี้:

public static void main(String[] args)
{
    int count = 0, errors = 0;
    int scale = 2;
    double factor = Math.pow(10, scale);
    MathContext mc = new MathContext(16, RoundingMode.DOWN);
    for (double x = 0.0; x < 1; x += 0.0001)
    {
        count++;
        double d = x;
        d = Math.round(d * factor) / factor;
        BigDecimal bd = new BigDecimal(d, mc);
        bd = bd.remainder(new BigDecimal("0.01"), mc);
        if (bd.multiply(BigDecimal.valueOf(100)).remainder(BigDecimal.ONE, mc).compareTo(BigDecimal.ZERO) != 0)
        {
            System.out.println(d + " " + bd);
            errors++;
        }
    }
    System.out.println(count + " trials " + errors + " errors");
}

ผลลัพธ์:

10001 trials 4401 errors

8
เคล็ดลับคือในข้อผิดพลาด 9251 ทั้งหมดของคุณผลการพิมพ์ยังคงถูกต้อง
Didier L

7
@DidierL มันไม่ได้ทำให้ฉันประหลาดใจ ฉันโชคดีมากที่ได้ทำ 'วิธีการเชิงตัวเลข' เป็นหลักสูตรการคำนวณครั้งแรกของฉันและได้รับการแนะนำตั้งแต่เริ่มต้นจนถึงจุดลอยตัวที่สามารถทำได้และไม่สามารถทำได้ โปรแกรมเมอร์ส่วนใหญ่ค่อนข้างคลุมเครือเกี่ยวกับเรื่องนี้
user207421

15
สิ่งที่คุณกำลังทำคือการ refuting ลอยไม่ได้แทนค่าทศนิยมจำนวนมากซึ่งฉันหวังว่าเราทุกคนจะเข้าใจ ไม่ใช่การปัดเศษที่ทำให้เกิดปัญหา ตามที่คุณยอมรับตัวเลขยังคงพิมพ์ตามที่คาดไว้
Peter Lawrey

8
การทดสอบของคุณใช้งานไม่ได้รอบ () และการทดสอบล้มเหลว 94% ของเวลา ideone.com/1y62CYภาพพิมพ์100 trials 94 errorsคุณควรเริ่มต้นด้วยการทดสอบที่ผ่านไปแล้วและแสดงให้เห็นว่าการแนะนำการปัดเศษเป็นการหยุดพักการทดสอบ
Peter Lawrey

6
หักล้างหักล้างที่นี่ ใช้ Math.round สำหรับช่วงนี้doubleโดยไม่มีข้อผิดพลาดideone.com/BVCHh3
Peter Lawrey

83

สมมติว่าคุณมี

double d = 9232.129394d;

คุณสามารถใช้ได้ BigDecimal

BigDecimal bd = new BigDecimal(d).setScale(2, RoundingMode.HALF_EVEN);
d = bd.doubleValue();

หรือไม่มี BigDecimal

d = Math.round(d*100)/100.0d;

ด้วยโซลูชั่นทั้งสอง d == 9232.13


2
ฉันคิดว่านี่เป็นทางออกที่ดีที่สุดสำหรับผู้ใช้ Java 1.5 (และด้านล่าง) หนึ่งความคิดเห็นอย่าใช้โหมดการปัดเศษ HALF_EVEN เนื่องจากมันมีพฤติกรรมที่แตกต่างกันสำหรับเลขคี่และคู่ (2.5 รอบถึง 2 ในขณะที่ 5.5 รอบถึง 6 เป็นตัวอย่าง) เว้นแต่เป็นสิ่งที่คุณต้องการ
IcedDante

4
วิธีแก้ปัญหาแรกถูกต้อง: วิธีที่สองไม่ทำงาน ดูที่นี่เพื่อพิสูจน์
user207421

1
@EJP: แม้แต่ทางออกแรกที่มีRoundingMode.HALF_UPก็ผิด 1.505ลองกับ BigDecimal.valueOf(d)วิธีที่ถูกต้องคือการใช้งาน
Matthias Braun

Matthias Braun แก้ปัญหาได้ดีดังนั้น 31 ups .. 1.505 ทศนิยมจะถูกเก็บไว้ในทศนิยมเป็นสองเท่า 1.50499998 ถ้าคุณต้องการใช้ 1.505 และแปลงจาก double เป็นทศนิยมจากนั้นคุณต้องแปลงเป็น Double.toString (x) ก่อน จากนั้นใส่ลงใน BigDecimal () แต่นั่นช้ามากและเอาชนะวัตถุประสงค์ของการใช้สองเท่าสำหรับความเร็วในตอนแรก
hamish

1
ขับวนวน 100k ด้วย BigDecimal (ใช้เวลา 225 ms) และ Math.round (2 ms) และนี่คือเวลา ... เวลาที่ใช้: 225 มิลลิวินาทีในการแปลงโดยใช้: 9232.13 เวลาที่ใช้: 2 มิลลิวินาทีในการแปลงเป็น : 9232.13 techiesinfo.com
user1114134

59

คุณสามารถใช้คลาส DecimalFormat

double d = 3.76628729;

DecimalFormat newFormat = new DecimalFormat("#.##");
double twoDecimal =  Double.valueOf(newFormat.format(d));

เหตุผลใดที่Double.valueOf()ถูกเลือกมากกว่าDouble.parseDouble()? valueOf()วิธีการส่งกลับDoubleวัตถุในขณะที่parseDouble()จะกลับdoubleดั้งเดิม ด้วยวิธีการเขียนรหัสปัจจุบันคุณยังสามารถนำกล่องอัตโนมัติไปใช้ในการส่งคืนเพื่อส่งไปยังดั้งเดิมที่twoDoubleตัวแปรของคุณคาดว่าจะเป็นการดำเนินการตามรหัสพิเศษ ฉันจะเปลี่ยนคำตอบเพื่อใช้parseDouble()แทน
ecbrodie

Double.parseDouble()ต้องการStringอินพุต
Ryde

38

Java How-to ของ Java โพสต์โซลูชันนี้ซึ่งยังสามารถใช้งานร่วมกับรุ่นก่อนหน้า Java 1.6

BigDecimal bd = new BigDecimal(Double.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();

33
double myNum = .912385;
int precision = 10000; //keep 4 digits
myNum= Math.floor(myNum * precision +.5)/precision;

2
ใช่นี่คือสิ่งที่ math.round ทำเพื่อหาจำนวนบวก แต่คุณได้ลองด้วยจำนวนลบหรือไม่? คนกำลังใช้ math.round ในโซลูชันอื่น ๆ เพื่อครอบคลุมกรณีของตัวเลขติดลบ
hamish

หมายเหตุ: Math.floor(x + 0.5)และMath.round(x)
Peter Lawrey

30

@Milhous: รูปแบบทศนิยมสำหรับการปัดเศษเป็นเลิศ:

คุณยังสามารถใช้

DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);

เพื่อให้แน่ใจว่าคุณมี 0 ต่อท้าย

ฉันจะเพิ่มว่าวิธีนี้ดีมากที่ให้กลไกการปัดเศษตัวเลขจริง - ไม่เพียง แต่มองเห็น แต่ยังเมื่อประมวลผล

สมมุติฐาน: คุณต้องใช้กลไกการปัดเศษในโปรแกรม GUI หากต้องการแก้ไขความแม่นยำ / ความแม่นยำของผลลัพธ์ผลลัพธ์เพียงแค่เปลี่ยนรูปแบบคาเร็ต (เช่นภายในวงเล็บ) ดังนั้น:

DecimalFormat df = new DecimalFormat("#0.######");
df.format(0.912385);

จะกลับมาเป็นเอาท์พุท: 0.912385

DecimalFormat df = new DecimalFormat("#0.#####");
df.format(0.912385);

จะกลับมาเป็นเอาท์พุท: 0.91239

DecimalFormat df = new DecimalFormat("#0.####");
df.format(0.912385);

จะกลับมาเป็นเอาท์พุท: 0.9124

[แก้ไข: หากรูปแบบคาเร็ตเป็นเช่นนั้น ("# 0. ##########") และคุณป้อนทศนิยมเช่น 3.1415926 เพื่อประโยชน์ของอาร์กิวเมนต์ DecimalFormat จะไม่สร้างขยะใด ๆ ( เช่นศูนย์ต่อท้าย) และจะกลับมา: 3.1415926.. หากคุณเป็นเช่นนั้น ได้รับมันเป็น verbose เล็ก ๆ น้อย ๆ สำหรับความชื่นชอบของบางคน - แต่เฮ้มันมีรอยความทรงจำที่ต่ำในระหว่างการประมวลผลและใช้งานง่ายมาก]

ความงามของ DecimalFormat ก็คือมันสามารถจัดการกับลักษณะที่ปรากฏของสตริงได้พร้อมกันรวมถึงระดับของความแม่นยำในการปัดเศษ Ergo: คุณได้รับประโยชน์สองประการสำหรับราคาของการติดตั้งโค้ดเดียว ;)


2
หากคุณต้องการตัวเลขทศนิยมในการคำนวณ (และไม่เพียง แต่สำหรับการส่งออก) จริงๆไม่ได้ใช้รูปแบบไบนารีจุดตามลอยdoubleเหมือน ใช้ BigDecimal หรือรูปแบบฐานสิบอื่น ๆ
Paŭlo Ebermann

20

นี่คือบทสรุปของสิ่งที่คุณสามารถใช้ถ้าคุณต้องการผลลัพธ์เป็นสตริง:

  1. DecimalFormat # setRoundingMode () :

    DecimalFormat df = new DecimalFormat("#.#####");
    df.setRoundingMode(RoundingMode.HALF_UP);
    String str1 = df.format(0.912385)); // 0.91239
  2. BigDecimal # setScale ()

    String str2 = new BigDecimal(0.912385)
        .setScale(5, BigDecimal.ROUND_HALF_UP)
        .toString();

นี่คือคำแนะนำเกี่ยวกับห้องสมุดที่คุณสามารถใช้ได้หากคุณต้องการdoubleผลลัพธ์ ฉันไม่แนะนำสำหรับการแปลงสตริง แต่เนื่องจาก double อาจไม่สามารถแสดงสิ่งที่คุณต้องการได้อย่างแน่นอน (ดูเช่นที่นี่ )

  1. ความแม่นยำจาก Apache Commons Math

    double rounded = Precision.round(0.912385, 5, BigDecimal.ROUND_HALF_UP);
  2. ฟังก์ชั่นจาก Colt

    double rounded = Functions.round(0.00001).apply(0.912385)
  3. ของใช้จาก Weka

    double rounded = Utils.roundDouble(0.912385, 5)

18

คุณสามารถใช้วิธีการยูทิลิตี้ต่อไปนี้ -

public static double round(double valueToRound, int numberOfDecimalPlaces)
{
    double multipicationFactor = Math.pow(10, numberOfDecimalPlaces);
    double interestedInZeroDPs = valueToRound * multipicationFactor;
    return Math.round(interestedInZeroDPs) / multipicationFactor;
}

@mariolpantunes: มันจะล้มเหลว ลองนี้: round(1.005,2);หรือround(0.50594724957626620092, 20);
Matthias Braun

มันได้ผล. แต่ทว่าลอยตัวและคู่ที่ไม่เป็นไปตามปกตินั้นเป็นการประมาณ ให้เราพิจารณาตัวอย่างแรกของคุณ หากคุณพิมพ์ผลลัพธ์ของ InterestInZeroDPs ก่อนหน้า Math.round มันจะพิมพ์ 100.49999999999999 คุณสูญเสียความแม่นยำเช่น Math.round ไปจนครบ 100 เนื่องจากลักษณะหรือลอยตัวและมีสองเท่ามีกรณีเขตแดนเมื่อมันไม่ทำงานอย่างถูกต้อง (ข้อมูลเพิ่มเติมที่นี่en.wikipedia.org/wiki/Floating_point#Accuracy_problems )
mariolpantunes

สองครั้งรวดเร็ว! ทศนิยมช้า คอมพิวเตอร์ไม่ต้องกังวลกับการคิดในรูปทศนิยม คุณต้องยอมแพ้ความแม่นยำทศนิยมเพื่อให้จุดลอยตัวเป็นสองเท่าได้อย่างรวดเร็ว
hamish

@hamish คำถามเกี่ยวกับความแม่นยำไม่ใช่เรื่องความเร็ว
user207421



7

ลองสิ่งนี้: org.apache.commons.math3.util.Precision.round (double x, int scale)

ดูที่: http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html

หน้าแรกของ Apache Commons Mathematics Library คือ: http://commons.apache.org/proper/commons-math/index.html

การดำเนินการภายในของวิธีนี้คือ:

public static double round(double x, int scale) {
    return round(x, scale, BigDecimal.ROUND_HALF_UP);
}

public static double round(double x, int scale, int roundingMethod) {
    try {
        return (new BigDecimal
               (Double.toString(x))
               .setScale(scale, roundingMethod))
               .doubleValue();
    } catch (NumberFormatException ex) {
        if (Double.isInfinite(x)) {
            return x;
        } else {
            return Double.NaN;
        }
    }
}

7

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

  • การจัดรูปแบบ : จัดรูปแบบสตริงเป็นสองเท่าได้อย่างง่ายดายด้วยจำนวนตำแหน่งทศนิยมที่แน่นอน
  • การแยก : วิเคราะห์ค่าที่จัดรูปแบบกลับเป็นสองเท่า
  • สถานที่เกิดเหตุ : รูปแบบและแยกวิเคราะห์โดยใช้สถานที่เริ่มต้น
  • สัญลักษณ์เอ็กซ์โปเนนเชียล : เริ่มใช้สัญกรณ์เอ็กซ์โปเนนเชียลหลังจากเกณฑ์ที่กำหนด

การใช้งานค่อนข้างง่าย :

(เพื่อประโยชน์ของตัวอย่างนี้ฉันใช้ภาษาที่กำหนดเอง)

public static final int DECIMAL_PLACES = 2;

NumberFormatter formatter = new NumberFormatter(DECIMAL_PLACES);

String value = formatter.format(9.319); // "9,32"
String value2 = formatter.format(0.0000005); // "5,00E-7"
String value3 = formatter.format(1324134123); // "1,32E9"

double parsedValue1 = formatter.parse("0,4E-2", 0); // 0.004
double parsedValue2 = formatter.parse("0,002", 0); // 0.002
double parsedValue3 = formatter.parse("3423,12345", 0); // 3423.12345

นี่คือคลาส :

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Locale;

public class NumberFormatter {

    private static final String SYMBOL_INFINITE           = "\u221e";
    private static final char   SYMBOL_MINUS              = '-';
    private static final char   SYMBOL_ZERO               = '0';
    private static final int    DECIMAL_LEADING_GROUPS    = 10;
    private static final int    EXPONENTIAL_INT_THRESHOLD = 1000000000; // After this value switch to exponential notation
    private static final double EXPONENTIAL_DEC_THRESHOLD = 0.0001; // Below this value switch to exponential notation

    private DecimalFormat decimalFormat;
    private DecimalFormat decimalFormatLong;
    private DecimalFormat exponentialFormat;

    private char groupSeparator;

    public NumberFormatter(int decimalPlaces) {
        configureDecimalPlaces(decimalPlaces);
    }

    public void configureDecimalPlaces(int decimalPlaces) {
        if (decimalPlaces <= 0) {
            throw new IllegalArgumentException("Invalid decimal places");
        }

        DecimalFormatSymbols separators = new DecimalFormatSymbols(Locale.getDefault());
        separators.setMinusSign(SYMBOL_MINUS);
        separators.setZeroDigit(SYMBOL_ZERO);

        groupSeparator = separators.getGroupingSeparator();

        StringBuilder decimal = new StringBuilder();
        StringBuilder exponential = new StringBuilder("0.");

        for (int i = 0; i < DECIMAL_LEADING_GROUPS; i++) {
            decimal.append("###").append(i == DECIMAL_LEADING_GROUPS - 1 ? "." : ",");
        }

        for (int i = 0; i < decimalPlaces; i++) {
            decimal.append("#");
            exponential.append("0");
        }

        exponential.append("E0");

        decimalFormat = new DecimalFormat(decimal.toString(), separators);
        decimalFormatLong = new DecimalFormat(decimal.append("####").toString(), separators);
        exponentialFormat = new DecimalFormat(exponential.toString(), separators);

        decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
        decimalFormatLong.setRoundingMode(RoundingMode.HALF_UP);
        exponentialFormat.setRoundingMode(RoundingMode.HALF_UP);
    }

    public String format(double value) {
        String result;
        if (Double.isNaN(value)) {
            result = "";
        } else if (Double.isInfinite(value)) {
            result = String.valueOf(SYMBOL_INFINITE);
        } else {
            double absValue = Math.abs(value);
            if (absValue >= 1) {
                if (absValue >= EXPONENTIAL_INT_THRESHOLD) {
                    value = Math.floor(value);
                    result = exponentialFormat.format(value);
                } else {
                    result = decimalFormat.format(value);
                }
            } else if (absValue < 1 && absValue > 0) {
                if (absValue >= EXPONENTIAL_DEC_THRESHOLD) {
                    result = decimalFormat.format(value);
                    if (result.equalsIgnoreCase("0")) {
                        result = decimalFormatLong.format(value);
                    }
                } else {
                    result = exponentialFormat.format(value);
                }
            } else {
                result = "0";
            }
        }
        return result;
    }

    public String formatWithoutGroupSeparators(double value) {
        return removeGroupSeparators(format(value));
    }

    public double parse(String value, double defValue) {
        try {
            return decimalFormat.parse(value).doubleValue();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return defValue;
    }

    private String removeGroupSeparators(String number) {
        return number.replace(String.valueOf(groupSeparator), "");
    }

}

7

หากคุณต้องการตัวเลขทศนิยมสำหรับการคำนวณ (และไม่เพียง แต่สำหรับเอาต์พุต) อย่าใช้รูปแบบทศนิยมอิงเลขฐานสองเช่นสองครั้ง

Use BigDecimal or any other decimal-based format.

ฉันใช้ BigDecimal สำหรับการคำนวณ แต่จำไว้ว่ามันขึ้นอยู่กับขนาดของตัวเลขที่คุณกำลังติดต่อด้วย ในการใช้งานส่วนใหญ่ของฉันฉันพบว่าการแยกวิเคราะห์จาก double หรือ integer เป็น Long นั้นเพียงพอสำหรับการคำนวณจำนวนมาก

ในความเป็นจริงฉันเพิ่งใช้การแจงส่วนยาวเพื่อให้ได้การแทนที่ถูกต้อง (เมื่อเทียบกับผลเลขฐานสิบหก) ใน GUI สำหรับตัวเลขที่มีขนาดใหญ่เท่ากับ ####################################################################### ################ อักขระ (เป็นตัวอย่าง)


6

เพื่อให้บรรลุสิ่งนี้เราสามารถใช้ตัวจัดรูปแบบนี้:

 DecimalFormat df = new DecimalFormat("#.00");
 String resultado = df.format(valor)

หรือ:

DecimalFormat df = new DecimalFormat("0.00"); :

ใช้วิธีนี้เพื่อรับทศนิยมสองครั้งเสมอ:

   private static String getTwoDecimals(double value){
      DecimalFormat df = new DecimalFormat("0.00"); 
      return df.format(value);
    }

การกำหนดค่านี้:

91.32
5.22
11.5
1.2
2.6

ใช้วิธีการที่เราสามารถรับผลลัพธ์นี้:

91.32
5.22
11.50
1.20
2.60

การสาธิตออนไลน์


5

ในกรณีที่บางคนยังต้องการความช่วยเหลือในเรื่องนี้ วิธีนี้ใช้ได้ผลดีสำหรับฉัน

private String withNoTrailingZeros(final double value, final int nrOfDecimals) {
return new BigDecimal(String.valueOf(value)).setScale(nrOfDecimals,  BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString();

}

ส่งคืน a String ด้วยเอาต์พุตที่ต้องการ


โปรดระบุเหตุผลของคุณสำหรับ downvoting ในความคิดเห็นมิฉะนั้นนั่นคือสิ่งที่เราเรียกว่าการข่มขู่
แอช M. O

4

ฉันเห็นด้วยกับคำตอบที่เลือกใช้DecimalFormat--- หรืออีกวิธีหนึ่งBigDecimalหรืออีกวิธีหนึ่ง

โปรดอ่านอัปเดตด้านล่างก่อน!

แต่ถ้าคุณไม่ต้องการที่จะปัดเศษค่าคู่และได้รับdoubleผลคุ้มค่าคุณสามารถใช้org.apache.commons.math3.util.Precision.round(..)ดังกล่าวข้างต้น การใช้BigDecimalงานนั้นช้าและสร้างขยะ

DoubleRounderยูทิลิตี้มีวิธีการที่คล้ายกัน แต่รวดเร็วและไร้ขยะในไลบรารีทศนิยม 4:

 double a = DoubleRounder.round(2.0/3.0, 3);
 double b = DoubleRounder.round(2.0/3.0, 3, RoundingMode.DOWN);
 double c = DoubleRounder.round(1000.0d, 17);
 double d = DoubleRounder.round(90080070060.1d, 9);
 System.out.println(a);
 System.out.println(b);
 System.out.println(c);
 System.out.println(d);

จะส่งออก

 0.667
 0.666
 1000.0
 9.00800700601E10

ดู https://github.com/tools4j/decimal4j/wiki/DoubleRounder-Utility

คำเตือน:ฉันมีส่วนร่วมในโครงการทศนิยม 4

อัปเดต: ตามที่ @iaforek ชี้ให้เห็นว่า DoubleRounder บางครั้งส่งกลับผลลัพธ์ที่ตรงกันข้าม เหตุผลก็คือมันทำการปัดเศษที่ถูกต้องทางคณิตศาสตร์ ตัวอย่างเช่นDoubleRounder.round(256.025d, 2)จะถูกปัดเศษลงเป็น 256.02 เนื่องจากค่าสองค่าที่แทนเป็น 256.025d ค่อนข้างเล็กกว่าค่าที่มีเหตุผล 256.025 และด้วยเหตุนี้จะถูกปัดเศษลง

หมายเหตุ:

  • พฤติกรรมนี้คล้ายกับตัวBigDecimal(double)สร้าง (แต่ไม่valueOf(double)ใช้ตัวสร้างสตริง)
  • ปัญหาสามารถหลบเลี่ยงได้ด้วยขั้นตอนการปัดเศษสองครั้งเพื่อความแม่นยำที่สูงขึ้นก่อน แต่มันซับซ้อนและฉันจะไม่เข้าไปดูรายละเอียดที่นี่

ด้วยเหตุผลเหล่านั้นและทุกอย่างที่กล่าวข้างต้นในโพสต์นี้ฉันไม่สามารถแนะนำให้ใช้ DoubleRounder


คุณมีเมตริกที่แสดงว่าโซลูชันของคุณมีประสิทธิภาพอย่างไรเมื่อเปรียบเทียบกับโซลูชันอื่น ๆ
iaforek

ฉันไม่ได้เปรียบเทียบกับโซลูชันอื่น ๆ แต่มีเกณฑ์มาตรฐาน jmh อยู่ในซอร์สโค้ด: github.com/tools4j/decimal4j/blob/master/src/jmh/java/org/ … ฉันใช้เบนช์มาร์กบน VM ผลลัพธ์มีอยู่เป็นไฟล์ csv ที่นี่: github.com/tools4j/decimal4j/wiki/Performance
marco

1
DoubleRounder ล้มเหลวสำหรับกรณีต่อไปนี้: DoubleRounder.round (256.025d, 2) - คาดว่า: 256.03, จริง: 256.02 หรือสำหรับ DoubleRounder.round (260.775d, 2) - คาดหวัง: 260.78, จริง: 260.77
iaforek

@iaforek: สิ่งนี้ถูกต้องเพราะ DoubleRounder ทำการปัดเศษที่ถูกต้องทางคณิตศาสตร์ อย่างไรก็ตามฉันยอมรับว่านี่ค่อนข้างขัดกับความเป็นจริงและจะปรับปรุงคำตอบของฉันตามนั้น
marco

3

ข้อมูลโค้ดด้านล่างแสดงวิธีการแสดงตัวเลข n เคล็ดลับคือการตั้งค่าตัวแปร pp เป็น 1 ตามด้วย n ศูนย์ ในตัวอย่างด้านล่างค่าตัวแปร pp มี 5 ศูนย์ดังนั้น 5 หลักจะปรากฏขึ้น

double pp = 10000;

double myVal = 22.268699999999967;
String needVal = "22.2687";

double i = (5.0/pp);

String format = "%10.4f";
String getVal = String.format(format,(Math.round((myVal +i)*pp)/pp)-i).trim();

3

หากคุณกำลังใช้DecimalFormatการแปลงdoubleเป็นStringมันตรงไปตรงมามาก:

DecimalFormat formatter = new DecimalFormat("0.0##");
formatter.setRoundingMode(RoundingMode.HALF_UP);

double num = 1.234567;
return formatter.format(num);

มีRoundingModeค่า enum หลายค่าให้เลือกขึ้นอยู่กับพฤติกรรมที่คุณต้องการ


3

ฉันมาที่นี่แค่ต้องการคำตอบง่ายๆเกี่ยวกับวิธีปัดเศษตัวเลข นี่คือคำตอบเพิ่มเติมเพื่อให้ที่

วิธีการปัดเศษตัวเลขใน Java

Math.round()กรณีที่พบมากที่สุดคือการใช้งาน

Math.round(3.7) // 4

ตัวเลขจะถูกปัดเศษเป็นจำนวนเต็มที่ใกล้ที่สุด .5ค่าปัดเศษขึ้น หากคุณต้องการพฤติกรรมการปัดเศษที่แตกต่างจากนั้นคุณสามารถใช้ฟังก์ชันคณิตศาสตร์อย่างใดอย่างหนึ่ง ดูการเปรียบเทียบด้านล่าง

รอบ

ตามที่ระบุไว้ข้างต้นรอบนี้เป็นจำนวนเต็มที่ใกล้ที่สุด .5ทศนิยมปัดเศษขึ้น intวิธีนี้ส่งกลับ

Math.round(3.0); // 3
Math.round(3.1); // 3
Math.round(3.5); // 4
Math.round(3.9); // 4

Math.round(-3.0); // -3
Math.round(-3.1); // -3
Math.round(-3.5); // -3 *** careful here ***
Math.round(-3.9); // -4

ceil

ค่าทศนิยมใด ๆ จะปัดขึ้นเป็นจำนวนเต็มถัดไป มันไปceilไอเอ็นจี doubleวิธีนี้ผลตอบแทน

Math.ceil(3.0); // 3.0
Math.ceil(3.1); // 4.0
Math.ceil(3.5); // 4.0
Math.ceil(3.9); // 4.0

Math.ceil(-3.0); // -3.0
Math.ceil(-3.1); // -3.0
Math.ceil(-3.5); // -3.0
Math.ceil(-3.9); // -3.0

ชั้น

ค่าทศนิยมใด ๆ จะปัดลงเป็นจำนวนเต็มถัดไป doubleวิธีนี้ผลตอบแทน

Math.floor(3.0); // 3.0
Math.floor(3.1); // 3.0
Math.floor(3.5); // 3.0
Math.floor(3.9); // 3.0

Math.floor(-3.0); // -3.0
Math.floor(-3.1); // -4.0
Math.floor(-3.5); // -4.0
Math.floor(-3.9); // -4.0

rint

นี่คล้ายกับรอบในค่าทศนิยมที่ปัดเศษเป็นจำนวนเต็มที่ใกล้เคียงที่สุด แต่แตกต่างround, .5ค่ารอบกับจำนวนเต็ม doubleวิธีนี้ผลตอบแทน

Math.rint(3.0); // 3.0
Math.rint(3.1); // 3.0
Math.rint(3.5); // 4.0 ***
Math.rint(3.9); // 4.0
Math.rint(4.5); // 4.0 ***
Math.rint(5.5); // 6.0 ***

Math.rint(-3.0); // -3.0
Math.rint(-3.1); // -3.0
Math.rint(-3.5); // -4.0 ***
Math.rint(-3.9); // -4.0
Math.rint(-4.5); // -4.0 ***
Math.rint(-5.5); // -6.0 ***

1
คุณกำลังแก้กรณีเฉพาะของการปัดเศษเป็น 0 ทศนิยม คำถามเดิมนั้นเป็นคำถามทั่วไปมากกว่า
lukas84

3

หากคุณใช้เทคโนโลยีที่มี JDK น้อยที่สุด นี่เป็นวิธีที่ไม่มี libs Java ใด ๆ :

double scale = 100000;    
double myVal = 0.912385;
double rounded = (int)((myVal * scale) + 0.5d) / scale;

สิ่งนี้จะล้มเหลวในกรณีที่ myVal นั้นมีค่าไม่น้อยกว่า 1 และมีเลขศูนย์หลังจากจุดทศนิยมเกินขนาดสเกล สมมติว่าคุณมี myVal = 9.00000000912385; ด้านบนจะส่งคืน 9.0 ฉันคิดว่าเราควรให้วิธีแก้ปัญหาที่ใช้งานได้ในทุกกรณีของ myVal ไม่เฉพาะสำหรับค่าที่คุณระบุไว้
tavalendo

@ user102859 ในตัวอย่างของคุณ 9.0 คือผลลัพธ์ที่ถูกต้อง ฉันไม่เข้าใจว่ามันจะล้มเหลวอย่างไร
Craigo

2

รูปแบบทศนิยมเป็นวิธีที่ดีที่สุดในการส่งออก แต่ฉันไม่ชอบมัน ฉันทำสิ่งนี้ตลอดเวลาเพราะมันคืนค่าสองเท่า ดังนั้นฉันสามารถใช้มันได้มากกว่าแค่เอาท์พุท

Math.round(selfEvaluate*100000d.0)/100000d.0;

หรือ

Math.round(selfEvaluate*100000d.0)*0.00000d1;

หากคุณต้องการค่าตำแหน่งทศนิยมขนาดใหญ่คุณสามารถใช้ BigDecimal แทน อย่างไรก็ตาม.0มีความสำคัญ หากไม่มีการปัดเศษ 0.33333d5 ให้คืน 0.33333 และอนุญาตให้มีเพียง 9 หลักเท่านั้น ฟังก์ชันที่สองที่ไม่มี.0ปัญหากับ 0.30000 ส่งคืน 0.30000000000000004


2

นี่คือคำตอบของฉัน:

double num = 4.898979485566356;
DecimalFormat df = new DecimalFormat("#.##");      
time = Double.valueOf(df.format(num));

System.out.println(num); // 4.89

1

ดังนั้นหลังจากอ่านคำตอบส่วนใหญ่ฉันรู้ว่าส่วนใหญ่ของพวกเขาจะไม่แม่นยำในความเป็นจริงการใช้BigDecimalดูเหมือนเป็นตัวเลือกที่ดีที่สุด แต่ถ้าคุณไม่เข้าใจวิธีการRoundingModeทำงานคุณจะสูญเสียความแม่นยำอย่างหลีกเลี่ยงไม่ได้ ฉันคิดเรื่องนี้เมื่อทำงานกับคนจำนวนมากในโครงการและคิดว่ามันจะช่วยให้คนอื่นมีปัญหาในการปัดเศษตัวเลข ตัวอย่างเช่น.

BigDecimal bd = new BigDecimal("1363.2749");
bd = bd.setScale(2, RoundingMode.HALF_UP);
System.out.println(bd.doubleValue());

คุณคาดหวังว่าจะได้1363.28ผลลัพธ์เป็นผลลัพธ์ แต่คุณจะได้ผลลัพธ์1363.27ที่ไม่คาดคิดหากคุณไม่รู้ว่าRoundingModeกำลังทำอะไรอยู่ ดังนั้นมองเข้าไปในออราเคิลเอกสารRoundingMode.HALF_UPคุณจะพบรายละเอียดดังต่อไปนี้

โหมดการปัดเศษเพื่อปัดไปทาง "เพื่อนบ้านที่ใกล้ที่สุด" เว้นแต่ว่าเพื่อนบ้านทั้งสองจะเท่ากันซึ่งในกรณีนี้จะปัดเศษขึ้น

ดังนั้นการรู้นี้เราตระหนักว่าเราจะไม่ได้รับการปัดเศษแน่นอนถ้าเราต้องการที่จะรอบต่อเพื่อนบ้านที่ใกล้ที่สุด ดังนั้นเพื่อให้ได้รอบที่เพียงพอเราจะต้องวนจากn-1ทศนิยมไปยังหลักทศนิยมที่ต้องการ ตัวอย่างเช่น.

private double round(double value, int places) throws IllegalArgumentException {

    if (places < 0) throw new IllegalArgumentException();

    // Cast the number to a String and then separate the decimals.
    String stringValue = Double.toString(value);
    String decimals = stringValue.split("\\.")[1];

    // Round all the way to the desired number.
    BigDecimal bd = new BigDecimal(stringValue);
    for (int i = decimals.length()-1; i >= places; i--) {
        bd = bd.setScale(i, RoundingMode.HALF_UP);
    }

    return bd.doubleValue();
}

1363.28นี้จะจบลงด้วยการให้เราส่งออกคาดว่าซึ่งจะเป็น


0

โดยที่dp = ตำแหน่งทศนิยมที่คุณต้องการและค่าเป็นสองเท่า

    double p = Math.pow(10d, dp);

    double result = Math.round(value * p)/p;

1
ผลิต1.0สำหรับและvalue = 1.005 dp = 2ใช้สิ่งนี้แทน
Matthias Braun

มันก็โอเคแมทตัวอย่างของคุณไม่ถูกต้อง เพราะ 1.005 ไม่สามารถแสดงเป็นทศนิยมได้สองเท่า มันจะต้องมีการจัดเก็บที่สูงกว่าหรือต่ำกว่า 1.005 นั่นคือมันถูกเก็บไว้เป็นสองเท่าเมื่อคุณคอมไพล์: 1.0049998 (มันไม่ได้ถูกจัดเก็บเป็นทศนิยมในโค้ดที่คอมไพล์ของคุณ สองเท่าที่กรณีขอบเช่นคุณมีความสำคัญ ถ้าเป็นเช่นนั้นคุณจะใช้ 3dp แล้วแปลงเป็นทศนิยมจากนั้นทำฟังก์ชันปัดเศษทศนิยมเช่นเดียวกับลิงก์ที่คุณโพสต์
hamish

1
@ ฉันไม่เห็นว่าแมทเธียสชจะมีผู้อ่านที่เชื่อว่า 'สิ่งใดก็ตามที่มีการรวบรวมค่าเป็นทศนิยม อย่าใส่คำเข้าไปในปากของคนอื่น
user207421

0

โปรดทราบว่า String.format () และ DecimalFormat สร้างสตริงโดยใช้ Locale เริ่มต้น ดังนั้นพวกเขาอาจเขียนตัวเลขที่จัดรูปแบบด้วยจุดหรือเครื่องหมายจุลภาคเป็นตัวคั่นระหว่างส่วนจำนวนเต็มและทศนิยม เพื่อให้แน่ใจว่าสตริงที่ปัดเศษอยู่ในรูปแบบที่คุณต้องการใช้ java.text.NumberFormat ดังนี้:

  Locale locale = Locale.ENGLISH;
  NumberFormat nf = NumberFormat.getNumberInstance(locale);
  // for trailing zeros:
  nf.setMinimumFractionDigits(2);
  // round to 2 digits:
  nf.setMaximumFractionDigits(2);

  System.out.println(nf.format(.99));
  System.out.println(nf.format(123.567));
  System.out.println(nf.format(123.0));

จะพิมพ์เป็นภาษาอังกฤษ (ไม่ว่าภาษาของคุณจะอยู่ที่ใด): 0.99 123.57 123.00

ตัวอย่างที่จะนำมาจาก Farenda - วิธีการแปลงคู่ String อย่างถูกต้อง


0

โดยทั่วไปการปัดเศษทำได้โดยการปรับขนาด: round(num / p) * p

/**
 * MidpointRounding away from zero ('arithmetic' rounding)
 * Uses a half-epsilon for correction. (This offsets IEEE-754
 * half-to-even rounding that was applied at the edge cases).
 */
double RoundCorrect(double num, int precision) {
    double c = 0.5 * EPSILON * num;
//  double p = Math.pow(10, precision); //slow
    double p = 1; while (precision--> 0) p *= 10;
    if (num < 0)
        p *= -1;
    return Math.round((num + c) * p) / p;
}

// testing edge cases
RoundCorrect(1.005, 2);   // 1.01 correct
RoundCorrect(2.175, 2);   // 2.18 correct
RoundCorrect(5.015, 2);   // 5.02 correct

RoundCorrect(-1.005, 2);  // -1.01 correct
RoundCorrect(-2.175, 2);  // -2.18 correct
RoundCorrect(-5.015, 2);  // -5.02 correct
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.