我正在开发Java / Groovy程序。我有一个双变量,它包含一个用户输入的数字。我真正想知道的是用户在小数点右侧键入了多少个数字。类似的东西:
double num = 3.14
num.getPlaces() == 2
当然,你不能用double来做这个,因为那是使用IEEE浮点数而且它都是近似值。
假设我无法获取用户键入的字符串,但只能访问已存储的值的double,有没有办法可以通过BigDecimal擦除那个double或者某些东西来获得“真实” “小数位数? (当双重显示在屏幕上时,它会正确,所以我认为有一种方法至少可以猜测好吗?)
答案 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()=地点数