2012-01-31 54 views
3

简单 - 与浮子左侧额
(即10.00000123而不是10)爪哇 - 除去浮剩菜优雅

这里,我去,我有一个困难时期:

我需要生成的列表具有恒定间隙浮如下 (实际上它的地图,我需要没关系retreive对象螺母)

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

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

每当我得到一个数字,我把它四舍五入到列表中最亲密的单元格。
可以说我得到0.051来检索列表A中的一个单元格 - 我返回0.05。
可以说让我在列表B中得到0.21来检索一个单元格 - 我返回0.25。

所以,我开始做这个

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

但比我得到了很多的时间0.2500001(浮动剩菜) 我需要一个聪明的方式来圆它。

可能采取的位数点后,再次做

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

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

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

,但我有时候有一个列表这样

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

,当我得到22 I retreive 20. 问题的小区是当我的10

Math.round(1/baseAssetStep) 
的间隙

返回0 - 我得到的NaN

+0

四舍五入是必要的吗?如果打印它们是问题,则可以将浮标保持原样并以特定的精度进行打印。例如,'String.format(“%。4f”,2.142133);'会四舍五入到四个地方...... – st0le 2012-01-31 08:12:33

+1

使用BigDecimal时,你需要确切的数字 – Dapeng 2012-01-31 08:13:03

+1

四舍五入是必须的。我需要知道有多少个小数位。可以说我得到了o.25f。我需要知道它是2位数字。但是如果我得到0.25000001呢? \ – Jeb 2012-01-31 08:17:05

回答

1

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

浮点数表示为二进制数小数数字,以及以10为底的简单表示的数字(例如0.01)不能用有限数量的二进制数字表示。这与基数3(仅为0.1)中的1/3容易相似,但基数10(0.333 ...)需要无限数量的数字。

如果您试图用基数为10的有限数字来表示1/3,则会得到一个近似值。同样,如果您尝试用基数2中的有限数字代表1/10(这就是floatdouble所做的),您将得到一个近似值,并且与1/100类似。你认为代码中的0.01是一个非常接近的数字,但不完全等于1/100。

有很多关于浮点的资源和与他们合作的难度。 http://floating-point-gui.de/是一个很好的开始。

+0

哇。一个网站专门为我的问题加上一个xkcd参考我的问题里面。这是真人秀。 – Jeb 2012-01-31 10:05:49

6

使用BigDecimal而不是float


Java Tutorials基本数据类型

浮动: [...]此数据类型不应该被用于精确的值,如货币。为此,您需要改为使用 java.math.BigDecimal类。数字和字符串包括 JavaDeveloper提供的BigDecimal和其他有用的类。

+1

会不会减慢系统(因为字符串解析)?你能举一个它的好处的例子吗?谢谢 – Jeb 2012-01-31 08:26:26

+1

你需要每秒多少次数来解析你的数字?你有没有衡量你的代码,发现这是一个瓶颈?你应该首先关心你的代码正确工作*这是你在使用'float'时很可能无法实现的。一旦你的代码是正确的,你可以看看如何使其更快。 – Bombe 2012-01-31 08:33:15

+0

Bombe, 答:我确实测量了我的代码。我刚刚发现MATH库占用了大量的运行时间(更准确的说,math.round()占用了我线程的35%)。这就是为什么我试图尽可能少地使用它。 B.我的代码目前工作正常。我现在在调整和修复部分。 – Jeb 2012-01-31 10:01:28

0

你需要一个恒定的差距,所以也许尝试另一种解决方案。拿出你的差距,让我们命名它G.绘制一个randow int - 让我们把它称为R,(如果你知道列表中的最大数量,你可以正确绘制它)。现在唯一要做的就是R * G,它会给你一个来自你列表的数字 - 当然有一些精确度,因为这是不可避免的使用float - 打印它只是使用格式。您也可以将其与BigDecimal结合使用;)

+0

好的解决方案。但是我得到9.22作为输入。我需要弄清楚对于给定列表,什么是R. – Jeb 2012-01-31 08:36:12

+0

: 0,2,4 ... 28 R将是新Random()。nextInt(28),如果列表将从0移位: 4 ,8 ... 32 R将是新Random()。nextInt(28)+ 4 如果你的疑问是我想到的 – PiotrkS 2012-01-31 09:52:08

1

首先,我会用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