Java Double 值 = 0.01 更改为 0.009999999999999787

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7408566/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 19:50:06  来源:igfitidea点击:

Java Double value = 0.01 changes to 0.009999999999999787

javanumbersdouble

提问by Alex

Possible Duplicate:
Why not use Double or Float to represent currency?

可能的重复:
为什么不使用 Double 或 Float 来表示货币?

I'm writing a basic command-line program in Java for my high school course. We're only working with variables right now. It's used to calculate the amount of bills and coins of whatever type in your change after a purchase. This is my program:

我正在为我的高中课程用 Java 编写一个基本的命令行程序。我们现在只处理变量。它用于计算购买后找零中任何类型的纸币和硬币的数量。这是我的程序:

class Assign2c {
    public static void main(String[] args) {
        double cost = 10.990;
        int paid = 20;
        double change = paid - cost;
        int five, toonie, loonies, quarter, dime, nickel, penny;

        five = (int)(change / 5.0);
        change -= five * 5.0;

        toonie = (int)(change / 2.0);
        change -= toonie * 2.0;

        loonies = (int)change;
        change -= loonies;

        quarter = (int)(change / 0.25);
        change -= quarter * 0.25;

        dime = (int)(change / 0.1);
        change -= dime * 0.1;

        nickel = (int)(change / 0.05);
        change -= nickel * 0.05;

        penny = (int)(change * 100);
        change -= penny * 0.01;

        System.out.println("   :" + five);
        System.out.println("   :" + toonie);
        System.out.println("   :" + loonies);
        System.out.println("##代码##.25:" + quarter);
        System.out.println("##代码##.10:" + dime);
        System.out.println("##代码##.05:" + nickel);
        System.out.println("##代码##.01:" + penny);
    }
}

It should all work but at the last step when there's $0.01 leftover, number of pennies should be 1 but instead, it's 0. After a few minutes of stepping into the code and outputting the change value to the console, I've found out that at the last step when change = 0.01, it changes to 0.009999999999999787. Why is this happening?

它应该都可以工作,但是在最后一步,当剩余 0.01 美元时,便士的数量应该是 1,但它是 0。在进入代码并将更改值输出到控制台几分钟后,我发现在最后一步,当 change = 0.01 时,它变为 0.009999999999999787。为什么会这样?

采纳答案by Amir Raminfar

Using doublefor currency is a bad idea, Why not use Double or Float to represent currency?. I recommend using BigDecimalor doing every calculation in cents.

使用doublefor currency 是一个坏主意,为什么不使用 Double 或 Float 来表示货币?. 我建议使用BigDecimal或以美分进行每项计算。

回答by Oliver Charlesworth

0.01 does not have an exact representation in floating-point (and neither do 0.1 nor 0.2, for that matter).

0.01 没有精确的浮点表示(就此而言,0.1 和 0.2 也没有)。

You should probably do all your maths with integer types, representing the number of pennies.

您可能应该使用整数类型进行所有数学运算,表示便士的数量。

回答by Jon Bright

doublesaren't kept in decimal internally, but in binary. Their storage format is equivalent to something like "100101multiplied by 10000" (I'm simplifying, but that's the basic idea). Unfortunately, there's no combination of these binary values that works out to exactly decimal 0.01, which is what the other answers mean when they say that floating point numbers aren't 100% accurate, or that 0.01 doesn't have an exact representation in floating point.

doubles内部不是以十进制保存,而是以二进制保存。它们的存储格式相当于“100101乘以10000”之类的东西(我在简化,但这是基本思想)。不幸的是,这些二进制值的组合没有精确到十进制 0.01,这就是其他答案的意思,当他们说浮点数不是 100% 准确时,或者 0.01 没有精确的浮点数表示观点。

There are various ways of dealing with this problem, some more complicated than others. The best solution in your case is probably to use ints everywhere and keep the values in cents.

有多种方法可以处理这个问题,有些方法比其他方法复杂。在您的情况下,最好的解决方案可能是在int任何地方使用s 并将值保持在美分。

回答by joshx0rfz

Floating point numbers are never 100% accurate (not quite true, see comments below). You should never compare them directly. Also integer rounding. The best way to do this would probably be to do it in cents and convert to dollars later (1 dollar == 100 cents). By converting to an integer you are losing precision.

浮点数从来都不是 100% 准确的(不完全正确,请参阅下面的评论)。你永远不应该直接比较它们。也是整数舍入。最好的方法可能是以美分做,然后再转换成美元(1 美元 == 100 美分)。通过转换为整数,您将失去精度。

回答by fvu

As the others already said, do not use doubles for financial calculations.

正如其他人已经说过的,不要在财务计算中使用双打。

This paper http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html(What Every Computer Scientist Should Know About Floating-Point Arithmetic) is a must-read to understand floating point math in computers.

这篇论文http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html(WhatEvery Computer Scientist should Know About Floating-Point Arithmetic)是了解浮点数学的必读之物在计算机中。

回答by Jerry Coffin

This is a problem that's arisen many times over. The bottom line is that on a computer that uses binary floating point (which Java requires), only fractions in which the denominator is a power of 2 can be represented precisely.

这是一个多次出现的问题。最重要的是,在使用二进制浮点数(Java 要求)的计算机上,只有分母为 2 的幂的分数才能精确表示。

The same problem arises in decimal. 1/3, for example, turns into 0.3333333..., because 3 isn't a factor of 10 (the base we're using in decimal). Likewise 1/17, 1/19, etc.

同样的问题出现在十进制中。例如,1/3 变成 0.3333333...,因为 3 不是 10 的因数(我们使用的十进制基数)。同样 1/17、1/19 等。

In binary floating point, the same basic problem arises. The main difference is that in decimal, since 5 is a factor of 10, 1/5 can be represented precisely (and so can multiples of 1/5). Since 5 is not a factor of 2, 1/5 cannotbe represented precisely in binary floating point.

在二进制浮点中,同样的基本问题出现了。主要区别在于在十进制中,由于 5 是 10 的因数,因此可以精确表示 1/5(1/5 的倍数也可以)。由于 5 不是 2 的因数,因此无法用二进制浮点数精确表示1/5 。

Contrary to popular belief, however, some fractions canbe represented precisely -- specifically those fractions whose denominators with only 2 as a prime factor (e.g., 1/8 or 1/256 can be represented precisely).

然而,与流行的看法相反,有些分数可以精确表示——特别是那些分母只有 2 作为质因数的分数(例如,1/8 或 1/256 可以精确表示)。

回答by Prodicus

I'm sure you know that some fractions' decimal representations terminate (e.g. .01) while some don't (e.g. 2/3=.66666...). The thing is that which fractions terminate changes depending on what base you're in; in particular, .01 doesn't terminate in binary, so even though double provides a lot of precision it can't represent .01 exactly. As others said, using BigDecimal or fixed-point integer computations (converting everything to cents) is probably best for currency; to learn more about floating point, you could start at The Floating-Point Guide- What Every Programmer Should Know About Floating-Point Arithmetic.

我确定您知道某些分数的小数表示终止(例如 .01),而有些则不终止(例如 2/3=.66666...)。问题是哪个分数终止取决于你在什么基础上;特别是,.01 不会以二进制结尾,所以即使 double 提供了很多精度,它也不能准确地表示 .01。正如其他人所说,使用 BigDecimal 或定点整数计算(将所有内容转换为美分)可能最适合货币;要了解有关浮点的更多信息,您可以从The Floating-Point Guide-What Every Programmer should Know About Floating-Point Arithmetic 开始

回答by l_39217_l

its a float(double)

它是一个浮点数(双)

You should not use it to compute money....

你不应该用它来计算金钱......

I recommend using int values and operate on pennys

我建议使用 int 值并对便士进行操作