我想要的是一种将双精度转换为字符串的方法,该字符串使用半向上舍入方法进行舍入-即,如果要舍入的小数为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中实现这一点的最佳方法是什么?


当前回答

假设你有

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

其他回答

因此,在阅读了大部分答案后,我意识到其中大多数答案都不精确,事实上,使用BigDecimal似乎是最佳选择,但如果你不了解RoundingMode的工作原理,你将不可避免地失去精度。我在一个项目中处理大数字时发现了这一点,并认为这可以帮助其他有舍入问题的人。例如

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

您希望得到1363.28作为输出,但如果您不知道RoundingMode在做什么,则最终会得到1363.27,这是不期望的。因此,查看Oracle文档,您将发现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的预期产量。

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

如果需要加倍,可以使用以下方法

double getRandom(int decimalPoints) {
    double a = Math.random();
    int multiplier = (int) Math.pow(10, decimalPoints);
    int b = (int) (a * multiplier);
    return b / (double) multiplier;
}

例如getRandom(2)

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

会给你一个BigDecimal。要从中获取字符串,只需调用BigDecimal的toString方法,或Java 5+的toPlainString方法来获取纯格式字符串。

示例程序:

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

@米尔豪斯:舍入的十进制格式非常好:

您也可以使用DecimalFormat df=新的DecimalFormat(“#.000000”);df.格式(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

[EDIT:如果插入符号格式是这样的(“#0.#############”)为参数起见,输入小数,例如3.1415926,DecimalFormat不产生任何垃圾(例如尾随零),并将返回:3.1415926…如果你有这种倾向。当然,这有点冗长对于一些开发人员来说-但是,嘿,它的内存占用量很低在处理过程中,并且非常容易实现。]

因此本质上,DecimalFormat的优点在于它同时处理字符串外观-以及舍入精度设置的级别。埃尔戈:你以一个代码实现的价格获得两个好处