Java:如何设置double值的精度?

129

最近我在处理数字时遇到一个情况,我希望根据数据库中存储的值设置双精度数值的精度为6位或4位。

例如,如果数据库中的精度设置为4位,则输出必须如下所示:

10.0000

我尝试使用 DecimalFormat 并使用字符串 ##.####,但每次都需要使用符号非常麻烦。

是否有更好的方法,比如以下示例:

Double value = 10.0;
value.setPrecision(4);

1
这并不是真正的重复... - Andreas L.
1
@AndreasL. 为什么不呢? - user207421
1
https://dev59.com/-nVC5IYBdhLWcg3w4Vb6 - OhadR
11个回答

340

您可以尝试使用BigDecimal来实现此目的。

Double toBeTruncated = new Double("3.5789055");

Double truncatedDouble = BigDecimal.valueOf(toBeTruncated)
    .setScale(3, RoundingMode.HALF_UP)
    .doubleValue();

14
为什么没有人点赞这个回答,它是完美的。 - user1613360
2
运行良好,可以删除“new Double”。 - halafi
1
调用 doubleValue() 方法时会有损失转换吗? - swapyonubuntu
2
尝试使用以下代码:double r1 = BigDecimal.valueOf(2.945777946674339E8D).setScale(3, RoundingMode.HALF_UP).doubleValue();--- 这样你会得到 2.94577794667E8。但是输出结果看起来与你的要求不同。 - Khanna111
1
@veritas 在那个特定的情况下它起作用了,因为0.5有一个精确的FP表示。大多数分数都没有。 - user207421
显示剩余3条评论

79

由于浮点数没有十进制位,而是二进制位,因此无法将double(或Double)的精度设置为指定数量的小数位。

如果您希望稍后使用该值,则需要通过BigDecimalDecimalFormat将其转换为十进制数。

另请参见我的答案此问题,以反驳不可避免的*100/100答案。


75

这是一个简单的方法:

String formato = String.format("%.2f");

它将精度设置为2个数字。

如果你只想打印输出,可以这样使用:

System.out.printf("%.2f",123.234);

3
只是为了澄清: double myDouble = 42.99; String formatted = String.format("%.2f", myDouble); - jdex
2
这并没有将数字精度设置为2位小数。它是将数字四舍五入到2位小数精度。这不是同一件事情。如果你要取整的数字由于精度不足而包含错误的值,那么取整是没有用的。 - Gili
@Gili,你能解释一下精度和舍入之间的区别吗?一些例子会更有帮助。 - Vipresh
根据@Vipresh Per在https://dev59.com/9WUq5IYBdhLWcg3wC79Q#14845954中的说法,`double`包含固定精度。如果您将0.1加十次,最终得到的double不严格等于1.0。这是因为浮点数不能准确地表示所有十进制数,即使只有一位(十进制)精度。如果您对已经不精确的数字调用`String.format()`,则无法保证结果精确到2位小数。 - Gili

27

为双精度值设置精度的好方法是使用DecimalFormat。要使用这个类,需要导入java.text.DecimalFormat并创建它的对象,例如:

To set precision for double values DecimalFormat 是好的技术。要使用这个类,导入java.text.DecimalFormat并创建其对象,例如

double no=12.786;
DecimalFormat dec = new DecimalFormat("#0.00");
System.out.println(dec.format(no));

所以这里会打印小数点后两位,将打印12.79


OP已经拒绝了这个解决方案,天知道为什么。 - user207421
1
@EJP 为什么?!! - Andreas L.
@AndreasL。我已经表达了我的困惑。我没有什么可补充的了。你应该向原帖发布者提出你的问题,而不是问我。 - user207421
如果你想要一定的精度,就不应该增加创建字符串(通过格式化)的额外步骤。更好的解决方案是只对Double值进行操作。精度不仅仅是表示问题。 - Younes El Ouarti

11

这对我有效:

public static void main(String[] s) {
        Double d = Math.PI;
        d = Double.parseDouble(String.format("%.3f", d));  // can be required precision
        System.out.println(d);
    }

4

以下是一种高效的方法,但有两个注意事项。

  1. 精度限制为“最大”N位(不是固定为N位)。
  2. 向下舍入数字(不是四舍五入)。

请在此处查看示例测试用例。

123.12345678 ==> 123.123
1.230000 ==> 1.23
1.1 ==> 1.1
1 ==> 1.0
0.000 ==> 0.0
0.00 ==> 0.0
0.4 ==> 0.4
0 ==> 0.0
1.4999 ==> 1.499
1.4995 ==> 1.499
1.4994 ==> 1.499

以下是代码。我上面提到的两个注意事项可以很容易地解决,但是对于我来说速度比准确性更重要,因此我将其留在这里。 与数学运算相比,像System.out.printf("%.2f",123.234);这样的字符串操作在计算上是昂贵的。在我的测试中,下面的代码(不带sysout)花费的时间是字符串操作的1/30。

public double limitPrecision(String dblAsString, int maxDigitsAfterDecimal) {
    int multiplier = (int) Math.pow(10, maxDigitsAfterDecimal);
    double truncated = (double) ((long) ((Double.parseDouble(dblAsString)) * multiplier)) / multiplier;
    System.out.println(dblAsString + " ==> " + truncated);
    return truncated;
}

3

doublefloat的精度由它们的大小和IEEE浮点类型实现方式固定。

另一方面,输出中的小数位数是格式问题。您说得对,重复输入相同的常量是不好的做法。您应该声明一个字符串常量,并使用其符号表示。

private static final String DBL_FMT = "##.####";

使用符号表示法,您可以在不搜索代码的情况下更改所有使用该常量的地方的精度。

2
扩展@EJP所说的,当处理双精度浮点数时,“精度”这个概念是极其棘手的。正如在https://dev59.com/h2865IYBdhLWcg3wnP2a#3730040中所讨论的那样,即使在任何精度下,你也无法将0.1表示为双精度浮点数,原因与你不能用有限精度来表示十进制下的1/3相同。
你需要考虑你要解决的问题,并思考以下问题:
a)我是否应该首先使用双精度浮点数;如果精度是一个相关的概念,那么使用双精度浮点数可能是一个错误。
b)如果双精度浮点数是合适的,那么什么是我的精度意义?如果你只是谈论显示,那么将逻辑封装在一个显示函数中,你只需要在一个地方处理它;即遵循DRY原则。

2
BigDecimal value = new BigDecimal(10.0000);
value.setScale(4);

使用10.01时会引发“需要四舍五入”的异常! - user12268814

0
public static String setPrecision(String number, int decimal) {
    double nbr = Double.valueOf(number);
    int integer_Part = (int) nbr;
    double float_Part = nbr - integer_Part;
    int floating_point = (int) (Math.pow(10, decimal) * float_Part);
    String final_nbr = String.valueOf(integer_Part) + "." + String.valueOf(floating_point);
    return final_nbr;
}

简单的解决方案是使用 => Double.parseDouble(String.format("%.3f", d)) - Sandeep M

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接