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

发布于 2024-08-13 03:35:49 字数 326 浏览 2 评论 0原文

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

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

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

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

I'm working on a Java/Groovy program. I have a double variable that holds a number that was typed in by a user. What I really want to know is how many numbers the user typed to the right of the decimal place. Something like:

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

Of course, you can't do this with a double since that's using IEEE floating points and it's all an approximation.

Assuming that I can't get at the string the user typed, but only have access to the double the value has been stored in, is there a way I can scrub that double though a BigDecimal or somesuch to get the "real" number of decimal places? (When the double gets displayed on the screen, it gets it right, so I assume there is a way to at least guess well?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

愿与i 2024-08-20 03:35:49

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

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

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

3.14
3.140
3.140000
3.14000000000000012434

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

如果可能的话,更改解析代码并在整个过程中使用 BigDecimal。

No, you can't... because there are lots of different strings the user could have typed in which would all be parsed to the same value.

The "real" number is almost certain to have more decimal places than the user typed. For example, 3.14 is stored as exactly 3.140000000000000124344978758017532527446746826171875. I don't think you want to display that to the user.

To make the problem clearer, you can't tell from the double value whether the user actually entered:

3.14
3.140
3.140000
3.14000000000000012434

Those four strings will all give you the same value - which should make it obvious that you can't possibly get back to what the user typed in.

If at all possible, change the parsing code and use BigDecimal throughout.

看海 2024-08-20 03:35:49

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

例如:

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

请注意,损坏是在将字符串转换为双精度数时造成的,而不是在将双精度数传递到 BigDecimal 时造成的。将双精度数输入 BigDecimal 只是提供了一种简单的方法来查看双精度数中的实际内容,因为 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
}

You are right there is something strange going on with doubles, what gets printed out is not the same as the contents of the variable.

for example:

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

Notice the damage is done in the conversion of the string to a double, not when the double is passed into the BigDecimal. Feeding the double to the BigDecimal just provides an easy way to see what's actually in the double, because toString is lying to you.

As Jon Skeet points out, accuracy is not an option here. However, assuming the value printed out on the screen is the result of calling toString on the double, you should be able to get a bigDecimal that's no more wrong than the toString version of the double, like this:

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

So you don't need to involve the BigDecimal, really, you can just do something like

groovy:000> d = 123.0001
===> 123.0001
groovy:000> s = d.toString()
===> 123.0001
groovy:000> s.substring(s.indexOf('.')).length() - 1
===> 4

Sorry to invalidate your comment by editing.

BTW here's something close to Steve's answer, translated to groovy. (I took out the test for the decimal point not found because if you run this on a machine with locales messed up so it isn't using a period for the decimal point I'd rather it blow up than return 0)

def getPlaces(d) {
    s = d.toString()
    s.substring(s.indexOf(".")).length() - 1
}
暗藏城府 2024-08-20 03:35:49

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

然后执行以下操作:

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

  • 仅获取分数。

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

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

  • 计算剩余的小数位

警告:这可能有点慢。

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

Yes, you can. At least if you don't mind that you sometimes get a wrong result.
We must assume that the user is lazy and has entered no more than ~12 significant decimal digits.

Then do the following:

  • Create a BigDecimal with the given double in the constructor. That will convert the double in an exact decimal representation.

  • Get only the fraction.

  • Get BigDecimal.toString() and find three or more consecutive '0' or '9' digits.

  • Cut off the fraction after those three digits. If the digits are nine, add a "1" at the
    end. After that remove all trailing zeroes.

  • Count the remaining fractional digits

Warning: This may be a bit slow.

If you only want the number of significant bits in the double you can get them much faster and easier, but decimal->binary conversion unfortunately uses almost all bits.

初与友歌 2024-08-20 03:35:49

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

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

我希望这有帮助..

根据你的评论更新
用户输入的。好点。

如果用户输入了一个看起来像没有小数点的整数(例如 5),并且您收到的是双精度数,那么您将得到的不是用户输入 - 因为她/他将输入 5,但您将收到 5.0。您无法判断用户实际上输入的是 5 还是 5.0。

If you absolutely must take a double, and you don't mind having a little utility method to run it through, you could write something like this. You said you don't have access to the String value of what the user entered, but is there a reason why you can't convert it to a string and do something like this?

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

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

then, instead of your example

 num.getPlaces() == 2

You can do

 getplaces(num) == 2

I hope this helps..

Update, given your comment
That the user entered. Good point.

If the user entered what looks like an integer (say, 5) without a decimal point, and you're receiving it as a double, then what you're going to get is something other than what the user entered - for s/he will have entered 5, but you'll have received 5.0. You'd have no way of telling whether the user actually entered 5 or 5.0.

惟欲睡 2024-08-20 03:35:49

如果您无法使用双精度数,请转换为字符串并计算小数点后的字符数。我认为有一些魔法可以将 1.99999999998 这样的数字显示为“2”

if you're stuck with a double, convert to a string and count the number of characters after the decimal point. I think there is some magic involved that displays numbers like 1.99999999998 as "2"

悲喜皆因你 2024-08-20 03:35:49

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

so if it is a user entered value. Accept the value as a String. Then you can use string functions to find the position of the "." and then subtract that number from the length of the string to get the number your looking for. Of course you'll want to trim() it, and verify it is in fact a number that was entered..

赏烟花じ飞满天 2024-08-20 03:35:49

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

Convert to BigDecimal.
BigDecimal.scale() = number of places

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文