3

我正在开发一个 Java/Groovy 程序。我有一个双变量,其中包含用户输入的数字。我真正想知道的是用户在小数点右边输入了多少个数字。就像是:

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

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

假设我无法获取用户键入的字符串,但只能访问存储值的双精度,有没有办法可以通过 BigDecimal 或类似的方法来清除该双精度以获得“真实”数量小数位?(当双重显示在屏幕上时,它是正确的,所以我认为有一种方法至少可以很好地猜测?)

4

7 回答 7

14

不,你不能……因为用户可以输入许多不同的字符串,这些字符串都会被解析为相同的值。

“真实”数字几乎肯定比用户键入的小数位数多。例如,3.14 存储为 3.140000000000000124344978758017532527446746826171875。我认为您不想将其显示用户。

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

3.14
3.140
3.140000
3.14000000000000012434

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

如果可能,请更改解析代码并始终BigDecimal使用。

于 2009-12-04T20:08:52.890 回答
3

你是对的,双打发生了一些奇怪的事情,打印出来的内容与变量的内容不同。

例如:

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

请注意,损坏是在将字符串转换为双精度时造成的,而不是在将双精度传递给 BigDecimal 时。将 double 提供给 BigDecimal 只是提供了一种简单的方法来查看 double 中的实际内容,因为 toString 是在骗你。

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

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

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

顺便说一句,这里的东西接近史蒂夫的回答,翻译成时髦的。(我对未找到的小数点进行了测试,因为如果你在一台机器上运行它并且语言环境搞砸了所以它没有使用小数点的句点,我宁愿它炸毁而不是返回 0)

def getPlaces(d) {
    s = d.toString()
    s.substring(s.indexOf(".")).length() - 1
}
于 2009-12-04T20:08:54.200 回答
2

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

然后执行以下操作:

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

  • 只获取分数。

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

  • 删掉这三位数之后的分数。如果数字是九位,则在末尾添加一个“1”。之后删除所有尾随零。

  • 计算剩余的小数位数

警告:这可能有点慢。

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

于 2009-12-07T22:16:25.493 回答
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。

于 2009-12-04T20:20:26.623 回答
0

如果您遇到双精度数,请转换为字符串并计算小数点后的字符数。我认为其中涉及一些魔术,将 1.99999999998 之类的数字显示为“2”

于 2009-12-04T20:09:40.263 回答
0

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

于 2009-12-04T20:10:15.393 回答
0

转换为 BigDecimal。BigDecimal.scale() = 位数

于 2012-01-29T17:58:35.313 回答