【发布时间】:2017-07-24 03:32:20
【问题描述】:
我正在优化 Java 的慢速 Double.toString 算法。我已经成功地重写了 Float.toString(速度提高了 400% 以上)。测试 Float.toString 的算法很容易,因为我可以在煮鸡蛋的时间里迭代 throw 所有可能的值(从 Integer.MIN_VALUE 到 Integer.MAX_VALUE)。
但是,以同样的方式测试 Double.toString 的准确性需要我从 Long.MIN_VALUE 迭代到 Long.MAX_VALUE。我可以在所有线程上开始这个测试并在我的余生中运行它,我敢打赌它不会完成。
需要明确的是,当我测试这个算法时,我只是简单地使用我的结果字符串并根据 java.lang.Double.toString(double d) 的结果调用 String.equals。如果它们匹配,我会转到下一个值。
我对算法的改进主要涉及消除不必要的精度。在计算 Double.toString 时,它使用一种特殊的 BigInteger 类来执行此操作。但是,我发现通过修剪无关紧要的位,我仍然可以获得相同的结果,并显着提高性能。
我认为我可以将所有值修剪到不超过 128 位(用偏移量替换修剪后的位)而不会失败我的测试,但是如何在不迭代每个值的情况下证明这一点?
我想我要问的是:原始算法的创建者如何在不测试所有可能的输入的情况下绝对确定他们的算法是正确的?
【问题讨论】:
-
and I bet it wouldn't finish是对的,因为浮点数代表实数,在 0 和 1 之间实际上有 无限 个数。更准确地说,在任意两个实数之间存在无限数量的其他实数。 -
这种情况的另一个结果是浮点数永远无法正确表示所有实数,只能表示适合它的实数。只有 non-significant 位,如果存储在浮点数中的当前值在 0 之后只有很少的数字,它们适合在那里并且可以二进制表示。例如 0.1 不能以二进制形式表示,因为它是 1/10。
-
出于实际目的,在 Java 中,Double.toString 有 2^64 个可能的输入。其中一些解析为相同的值(NaN)。一半是阴性的。有负无穷和正无穷,负零和正零。一些可以使用稍微修改的 Long.toString 算法来解决。然而,大多数是通过找到值 b 和 s 来计算的,使得 (b/s)*10^decExp = double 值。十进制指数是根据需要估计和调整的。
-
@JohnSmith 您的 cmets 相互矛盾。您可以轻松(尽管这很耗时)迭代所有可能的浮点数,因为 它们并不代表每个实数,正如您在第一条评论中所说的那样;您的第二个是准确的,因为有限精度意味着一些“附近”数字聚集在一起,并且二进制表示具有无限位数的数字被截断。有限的精度意味着是的,可以迭代每个浮点数,只要从 32 0 表示的那个开始,然后像二进制整数一样递增它直到 32 1。
标签: java double tostring floating