有没有办法在java double中获得小数点后的位数?

时间:2009-12-04 20:04:57

标签: java groovy floating-point approximation

我正在开发Java / Groovy程序。我有一个双变量,它包含一个用户输入的数字。我真正想知道的是用户在小数点右侧键入了多少个数字。类似的东西:

double num = 3.14
num.getPlaces() == 2

当然,你不能用double来做这个,因为那是使用IEEE浮点数而且它都是近似值。

假设我无法获取用户键入的字符串,但只能访问已存储的值的double,有没有办法可以通过BigDecimal擦除那个double或者某些东西来获得“真实” “小数位数? (当双重显示在屏幕上时,它会正确,所以我认为有一种方法至少可以猜测好吗?)

7 个答案:

答案 0 :(得分:14)

不,你不能......因为用户可以输入许多不同的字符串,所有字符串都将被解析为相同的值。

“真实”数字几乎肯定会比用户输入的位数多一些。例如,3.14存储为3.140000000000000124344978758017532527446746826171875。我认为您不想向用户显示

为了使问题更清楚,您无法从双重值中判断用户是否实际输入了:

3.14
3.140
3.140000
3.14000000000000012434

这四个字符串都会给你相同的值 - 这应该很明显你不能可能回到用户键入的内容。

如果可以所有,请更改解析代码并始终使用BigDecimal

答案 1 :(得分:3)

你是对的,双打有一些奇怪的事情,打印出来的内容与变量的内容不一样。

例如:

groovy:000> "123.0001".toBigDecimal()
===> 123.0001
groovy:000> "123.0001".toDouble()
===> 123.0001
groovy:000> new BigDecimal("123.0001".toDouble())
===> 123.000100000000003319655661471188068389892578125

请注意,损坏是在将字符串转换为double时完成的,而不是在将double传递给BigDecimal时。将big加到BigDecimal只是提供了一种简单的方法来查看double中的实际内容,因为toString对你说谎。

正如Jon Skeet指出的那样,准确性不是一个选择。但是,假设屏幕上打印的值是在double上调用toString的结果,那么你应该能够得到一个bigDecimal,它不会比double的toString版本错误,如下所示:

groovy:000> d = "123.0001".toDouble()
===> 123.0001
groovy:000> d.toString()
===> 123.0001
groovy:000> new BigDecimal(d.toString())
===> 123.0001

所以你不需要涉及BigDecimal,真的,你可以做一些像

这样的事情
groovy:000> d = 123.0001
===> 123.0001
groovy:000> s = d.toString()
===> 123.0001
groovy:000> s.substring(s.indexOf('.')).length() - 1
===> 4

很抱歉通过编辑使您的评论无效。

顺便说一句,这里有一些接近史蒂夫答案的东西,翻译成groovy。 (我没有找到小数点的测试结果,因为如果你在一台机器人上运行这个乱码,因为它没有使用小数点的时间段我宁愿爆炸而不是返回0)

def getPlaces(d) {
    s = d.toString()
    s.substring(s.indexOf(".")).length() - 1
}

答案 2 :(得分:2)

是的,你可以。至少如果你不介意你有时会得到错误的结果。 我们必须假设用户是懒惰的并且输入的数字不超过~12个有效十进制数字。

然后执行以下操作:

  • 在构造函数中使用给定的double创建一个BigDecimal。这将以精确的十进制表示形式转换double。

  • 只获得分数。

  • 获取BigDecimal.toString()并找到三个或更多连续的'0'或'9'数字。

  • 切掉这三位数后的分数。如果数字为9,则在数字处添加“1” 结束。之后删除所有尾随零。

  • 计算剩余的小数位数

警告:这可能有点慢。

如果您只想要双倍中的有效位数,则可以更快更容易地获得它们,但十进制 - >二进制转换不幸地使用了几乎所有位。

答案 3 :(得分:1)

如果你绝对必须加倍,你不介意用一点实用工具来完成它,你可以写这样的东西。你说你无法访问用户输入的字符串值,但有没有理由不能将它转换为字符串并执行类似的操作?

static int getPlaces(double num) {
    String numString = String.valueOf(num);

    return numString.indexOf(".0")==numString.length()-2?0:numString.length()-numString.indexOf(".")-1;
}

然后,而不是你的例子

 num.getPlaces() == 2

你可以做到

 getplaces(num) == 2

我希望这有帮助..

根据您的评论更新 That the user entered. Good point.

如果用户输入的内容看起来像一个没有小数点的整数(例如5),并且您将其作为双精度接收,那么您将获得的不是用户输入的内容 - 他/她将进入5,但你将获得5.0。您无法确定用户是否实际输入了5或5.0。

答案 4 :(得分:0)

如果你坚持使用double,则转换为字符串并计算小数点后的字符数。我认为有一些魔术可以将像1.99999999998这样的数字显示为“2”

答案 5 :(得分:0)

所以如果是用户输入的值。将值作为String接受。然后你可以使用字符串函数来找到“。”的位置。然后从字符串的长度中减去该数字,以获得您要查找的数字。当然你需要修剪()它,并验证它实际上是输入的数字..

答案 6 :(得分:0)

转换为BigDecimal。 BigDecimal.scale()=地点数