【问题标题】:java - remove float leftovers elegantlyjava - 优雅地删除浮动剩菜
【发布时间】:2012-01-31 08:06:08
【问题描述】:

简而言之 - 我很难处理剩余的浮动
(即 10.00000123 而不是 10)

我来了:

我需要生成具有恒定间隙的浮点列表,如下所示 (实际上它是一张地图,我需要检索对象,但没关系)

列表 A:0.25、0.5、0.75、1、...

列表 B:0.01, 0.02, 0.03, 0.04, ...

每次我得到一个数字时,我都会将它四舍五入到列表中最近的单元格。
假设我得到 0.051 来检索列表 A 中的单元格 - 我返回 0.05。
假设我得到 0.21 来检索列表 B 中的单元格 - 我返回 0.25。

所以我开始这样做了

float a = Math.round(Value / step) * step;

但比我得到很多时间 0.2500001 (float leftovers ) 我需要一个聪明的方法来解决它。

也许通过取点后面的位数然后再做一次

Math.round(Value / 100) * 100;?

有没有更聪明的方法? 我试过doig这个

        final float factor = Math.round(1 / step);
        final float value = (float) Math.round(value * factor) / factor;

但我有时会有这样的列表

列表 A:10, 15, 20, 25, 30, ...

当我得到 22 时,我检索了 20 的单元格。 问题是当我得到 10 的差距时

Math.round(1 / baseAssetStep) 

返回 0 - 我得到 NaN

【问题讨论】:

  • 是否需要四舍五入?如果打印它们是问题,您可以将浮动保留原样并简单地以特定精度打印。例如,String.format("%.4f",2.142133); 将精确地四舍五入...
  • 当你想要精确的数字时使用 BigDecimal
  • 四舍五入是必须的。我需要知道有多少小数位。可以说我得到 o.25f 。我需要知道它是 2 位数字。但是如果我得到 0.25000001 怎么办? \

标签: java floating-point rounding


【解决方案1】:

使用BigDecimal 代替float


来自原始数据类型Java Tutorials

float: [...] 这种数据类型绝不能用于精确值,例如货币。为此,您将需要使用 java.math.BigDecimal 类。数字和字符串封面 Java 平台提供的 BigDecimal 和其他有用的类。

【讨论】:

  • 这会不会减慢系统速度(因为字符串解析)?你能举例说明它的好处吗?谢谢
  • 你需要每秒多少百万次来解析你的数字?您是否测量过您的代码并发现这是一个瓶颈?您首先应该关注您的代码是否正确工作,这是您在使用floats 时很可能无法实现的。一旦你的代码是正确的,你可以看看如何让它更快。
  • Bombe, A. 我确实测量了我的代码。我刚刚发现 MATH 库占用了很大一部分运行时间(更准确地说 math.round() 占用了我线程的 35%)。这就是为什么我试图尽可能少地使用它。 B. 我的代码目前运行良好。我现在在调整和修复部分。
  • 总时间的 35%?您还必须考虑绝对值。例如 100 毫秒的 35% 并不算多
【解决方案2】:

首先,我会改用doublelong,因为它们的精度要高得多。如果您确实需要,请使用 BigDecimal,但在现实世界中很难找到 doublelong 无法完成这项工作的情况。

double d = 10.00000123;
double r = Math.round(d * 10000) / 10000.0;

或使用定点精度的 long。

long l = 100000; // the actual value * 10000

定点精度的一个常见用例是金钱。不要在double 中使用美元,而是在long 甚至int 中使用美分。

【讨论】:

    【解决方案3】:

    简而言之,“这些不是您要查找的数字。”

    浮点数表示为二进制小数,而一些可以很容易地以 10 为基数表示的数字(例如 0.01)不能用有限个二进制数表示。这类似于以 3 为底的 1/3 很容易(它只是 0.1),但需要以 10 为底的无限位数(0.333...)。

    如果您尝试用以 10 为底的有限位数表示 1/3,您将得到一个近似值。类似地,如果您尝试用以 2 为底的有限位数表示 1/10(floatdouble 所做的),您将得到一个近似值,与 1/100 类似。您认为代码中的 0.01 实际上是一个非常接近但不完全等于 1/100 的数字。

    有很多关于浮点数和使用它们的困难的资源。 http://floating-point-gui.de/ 是一个很好的起点。

    【讨论】:

    • 哇。一个专门针对我的问题的网站,以及其中对我的问题的 xkcd 引用。这是杜鲁门表演。
    【解决方案4】:

    你需要一个恒定的差距,所以也许尝试另一种解决方案。拿你的差距,让我们把它命名为 G。绘制一个随机整数 - 我们称之为 R,(如果你知道列表中的最大数字,你可以正确地绘制它)。现在唯一要做的就是 R*G 它将为您提供列表中的一个数字 - 当然具有一定的精度,因为使用浮点数是不可避免的 - 只需使用格式即可打印它。您也可以将它与 BigDecimal 结合使用;)

    【讨论】:

    • 不错的解决方案。但我得到 9.22 作为输入。我需要弄清楚 R 是什么。
    • 对于给定的列表:0,2,4...28 R 将是新的 Random().nextInt(28),如果列表将从 0 移动:4,8...32如果您的疑问是我的想法,R 将是 new Random().nextInt(28) + 4
    猜你喜欢
    • 1970-01-01
    • 2011-12-08
    • 2011-05-19
    • 2011-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-05
    • 1970-01-01
    相关资源
    最近更新 更多