浮点运算不能产生精确的结果

x6yk4ghg  于 2021-07-05  发布在  Java
关注(0)|答案(7)|浏览(299)

这个问题在这里已经有答案了

浮点数学坏了吗((31个答案)
5年前关门了。
我需要用java做一些浮点运算,如下代码所示:

public class TestMain {
    private static Map<Integer, Double> ccc = new HashMap<Integer, Double>() {
      { put(1, 0.01); put(2, 0.02); put(3, 0.05); put(4, 0.1); put(6, 0.2);
        put(10, 0.5); put(20, 1.0); put(30, 2.0); put(50, 5.0); put(100, 10.0);
      }
    };

    Double increment(Double i, boolean up) {
        Double inc = null;

        while (inc == null) {
            inc = ccc.get(i.intValue());

            if (up)
                --i;
            else
                ++i;
        }
        return inc;
    }

    public static void main(String[] args) {
        TestMain tt = new TestMain();

        for (double i = 1; i < 1000; i += tt.increment(i, true)) {
            System.out.print(i + ",");
        }
    }
}

这是为了模拟betfair微调器小部件输出的值的范围。
java中的浮点算法似乎会引入一些意想不到的错误。例如,我得到2.180000000000001而不是2.18。浮点数的用途是你不能相信对它们执行算术的结果?我怎样才能避开这个问题?

omqzjyyz

omqzjyyz1#

顺便说一句,您可以尝试使用这个函数来确保(小数位数不要太多)您的数字将被重新格式化,只保留您需要的小数。
http://pastebin.com/cacer0xk n 你的数字有很多小数吗。 Math.PI ), numberOfDecimals 是所需的最大小数位数(例如,3.14为2或3.151为3)。
从理论上讲,将 numberOfDecmals ,它也将截断数字的整数低位。e、 g推杆 n=1588.22 以及 numberOfDecimals=-2 ,函数将返回 1500.0 .
如果有什么问题,请告诉我。

c86crjj0

c86crjj02#

通过使用格式化输出,可以使程序的输出看起来更像您期望的那样。
http://java.sun.com/javase/6/docs/api/java/util/formatter.html
很明显,底层的浮点运算仍然是一样的,但至少输出的可读性会更好。
例如,要将结果四舍五入到小数点后两位:

System.out.print(String.format(".2f", i) + ",");
nxagd54h

nxagd54h3#

从哲学的Angular 来说,我想知道:今天大多数计算机cpu都内置了对整数运算和浮点运算的支持,但不支持十进制运算。为什么不?因为这个舍入问题,我已经有好几年没有写过浮动可用的应用程序了。你当然不能用它们来计算金额:没有人愿意在“42320003美元”的销售收据上打印价格。没有会计会接受“我们可能会在这里和那里的一分钱,因为我们使用二进制分数和舍入错误”。
浮子可以用来测量,比如距离或温度,在这里没有“精确答案”这样的东西,无论如何,你必须在某个点上四舍五入到你的仪器的精度。我想对于在化学实验室编写计算机程序的人来说,浮点数是经常使用的。但对我们这些商界人士来说,它们几乎毫无用处。
早在我在大型机上编程的古代,ibm360系列cpu就内置了对压缩十进制算法的支持。它们存储字符串,其中每个字节包含两个十进制数字,即前四位的值从0到9,后四位的值也是,cpu有算术函数来处理它们。为什么英特尔不能这样做?然后java可以添加一个“decimal”数据类型,我们就不需要所有额外的垃圾了。
当然,我不是说要废除浮动。只要加上小数。
哦,好吧,随着伟大的社会运动的进行,我不认为这是一个会产生很多民众的兴奋或街头骚乱。

7xzttuei

7xzttuei4#

你可以在你的机器上写一些代码来计算epsilon。我相信std::c++定义了它,它的定义方式取决于您使用的是什么。

private static float calcEpsilonFloat() {
    float epsi = 1.0f;

    while ((float) (1.0 + (epsi / 2.0)) != 1.0)
    {
       epsi /= 2.0f;
    }

    return epsi;
}

我唯一担心epsilon的时候是在比较阈值信号的时候。即使这样,我也不确定我是否真的需要担心它,根据我的经验,如果你关心epsilon,你可能需要先考虑其他一些问题。

ua4mk5z4

ua4mk5z45#

浮点数使用二进制分数而不是十进制分数。也就是说,你已经习惯了由十分之一位、百分之一位、千分之一位等组成的小数,d1/10+d2/100+d3/1000。。。但是浮点数是二进制的,所以它们有半位数、四分之一位数、八分之一位数等等。。。
许多小数不能精确地用任何有限个二进制数字来表示。例如,1/2是没有问题的:十进制是.5,二进制是.1。3/4是十进制.75,二进制.11。但1/10在十进制中是干净的.1,但在二进制中是.000110011。。。“0011”永远在重复。由于计算机只能存储有限数量的数字,因此在某些情况下,这些数字必须被切掉,因此答案并不精确。当我们把输出转换回十进制时,我们得到一个奇怪的数字。
正如乔恩斯基特所说,如果你需要精确的小数点,使用bigdecimal。如果性能有问题,您可以自己滚动小数。比如,如果你知道你总是想要精确的3个小数位,并且数字不会超过一百万左右,你可以简单地使用int,假设3个小数位,在做算术时做必要的调整,并编写输出格式函数将小数点插入正确的位置。但是99%的时间性能不是一个值得麻烦的大问题。

6qqygrtg

6qqygrtg6#

如果需要精确的十进制值,应该使用 java.math.BigDecimal . 然后阅读“每一位计算机科学家都应该知道的浮点运算”作为获得这些结果的背景。
(我有一篇以.net为中心的文章,你可能会发现这篇文章更容易阅读,当然也更短。java和.net之间的差异对于理解这个问题基本上是无关的。)

dba5bblo

dba5bblo7#

浮点数是不精确的,特别是因为它们是以二进制分数(1/2,1/4,1/8,1/16,1/32,…)而不是十进制分数(1/10,1/100,1/1000,…)工作的。只要定义你觉得“足够接近”的东西,然后使用 Math.abs(a-b) < 0.000001 .

相关问题