【问题标题】:Is there a way to get the number of places after the decimal point in a java double?有没有办法在java double中获取小数点后的位数?
【发布时间】:2010-12-23 09:20:11
【问题描述】:

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

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

当然,您不能使用双精度数来执行此操作,因为它使用的是 IEEE 浮点数,而且都是近似值。

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

【问题讨论】:

  • 脚注:由于这是一个混合的 Java/Groovy 代码库,任何使用基于 groovy 的魔法的解决方案都将受到欢迎。
  • 您想知道用户在小数点后输入了多少位,或者小数点后将打印多少位?这是两个完全不同的问题。
  • 用户输入的。好点子。

标签: java groovy floating-point approximation


【解决方案1】:

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

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

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

3.14
3.140
3.140000
3.14000000000000012434

这四个字符串都会为您提供相同的值 - 这应该表明您无法可能返回用户输入的内容。

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

【讨论】:

  • Nitpick:如果您在代码中使用 3.14,则应考虑改用 Math.PI
  • @R.Bemrose:你相信数字 3.14 永远不会出现在任何地方,但它实际上意味着 pi?
  • Guys 3.14 只是一个例子。我们谈论的是任意用户输入的双打。
  • 而且,为了记录,在我为王(或至少是项目经理)的世界中,所有这些双打都将成为 BigDecimals。可悲的是,我认为这种变化可能会被认为有点超出范围。 ;)
  • 3.14 一个 PI - 这让我想起了著名的印第安纳 Pi 法案:en.wikipedia.org/wiki/Indiana_Pi_Bill
【解决方案2】:

你说得对,双打出现了一些奇怪的情况,打印出来的内容与变量的内容不同。

例如:

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
}

【讨论】:

  • 相信我,如果我有选择的话,我不会。但是,你知道,现有的代码库等等。我什至没有在收集数据的模块上工作,所以我只是得到了一个双手。 :)
  • 伙计,至少我的不是财务数字,所以偶尔的舍入误差是可以的。
  • “注意损坏是在将字符串转换为双精度时完成的......”是一个有趣的短语。对于普通读者来说,“损害”是 double 只是一个近似值。 min double 和 max double 之间的大部分数字是不可表示的。它尽其所能。 :) Double.toString() 试图重新近似我们的意思,因为我们的意思更可能是 3.14 而不是 3.1400000000000001243... 等等。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 问题特别提到无法访问字符串,只能访问双精度值。
    【解决方案5】:

    如果您绝对必须使用 double,并且您不介意使用一些实用方法来运行它,那么您可以编写类似这样的内容。您说您无权访问用户输入的字符串值,但您是否有理由无法将其转换为字符串并执行此类操作?

    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。

    【讨论】:

    • 顺便说一句,对不起,我没有一种编写该方法的常规方式。我只知道java..
    【解决方案6】:

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

    然后执行以下操作:

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

    • 只获取分数。

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

    • 截去这三位数之后的分数。如果数字是九位,在后面加一个“1” 结尾。之后删除所有尾随零。

    • 计算剩余的小数位数

    警告:这可能有点慢。

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

    【讨论】:

      【解决方案7】:

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

      【讨论】:

        猜你喜欢
        • 2014-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多