如何在Java中將數字四捨五入到小數點後n位

我想要的是一種將雙精度數轉換爲使用Half-up方法取整的字符串的方法-即,若是要取整的小數爲5,則始終將其取整爲下一個數字。 這是大多數人在大多數狀況下指望的四捨五入標準方法。 html

我也但願只顯示有效數字-即不該有任何尾隨零。 java

我知道這樣作的一種方法是使用String.format方法: git

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

返回: api

0.91239

這很好,可是即便數字不重要,它也始終顯示5位小數: oracle

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

返回: 測試

0.91230

另外一種方法是使用DecimalFormatterspa

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

返回: 線程

0.91238

可是,如您所見,這使用了半數舍入。 若是前一位是偶數,它將四捨五入。 我想要的是這樣的: code

0.912385 -> 0.91239
0.912300 -> 0.9123

用Java實現此目標的最佳方法是什麼? orm


#1樓

正如其餘一些人指出的那樣,正確的答案是使用DecimalFormatBigDecimal 。 浮點沒有小數因此你不可能圓/截形到他們擺在首位的具體數量。 您必須使用十進制基數,這就是這兩個類的做用。

我將如下代碼做爲該線程中全部答案的反示例,甚至在整個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

編輯:爲了解決下面的一些評論,我使用BigDecimalnew 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

#2樓

Real的Java How-to 發佈了此解決方案,該解決方案也與Java 1.6以前的版本兼容。

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

#3樓

假設valuedouble ,則能夠執行如下操做:

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

這是5位數字的精度。 零數表示小數位數。


#4樓

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

#5樓

使用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.77395這樣的值實際上在內部沒有該確切值。 它能夠稍大或略小。 若是內部值稍小,則不會舍入到2.7740。 爲了解決這種狀況,您須要瞭解所使用的值的準確性,並在舍入以前添加或減去該值。 例如,當您知道本身的值在6位數字以內是正確的,而後將其四捨五入時,請將精度添加到值中:

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

要舍入,請減去精度。

相關文章
相關標籤/搜索