在 Java 中将浮点数转换为 int 的异常



正如标题所述,我正在尝试将一些浮点数转换为整数,并且我看到了几个值的一些异常。我有一个方法试图将浮点数的小数部分(例如.45 from 123.45)转换为字符串表示形式,其中它输出为45/100.

问题是,对于0.35, 0.45, 0.65 and 0.95我分别得到0.34, 0.44, 0.64 and 0.94。这是我的实现:

public String convertDecimalPartToString(float input){
int numberOfDigits = numberOfDigits(input);
System.out.println(numberOfDigits);
String numerator = Integer.toString((int) (input * Math.pow(10, numberOfDigits)));
String denominator = Integer.toString((int) Math.pow(10, numberOfDigits));
return numerator + "/" + denominator;
}
public int numberOfDigits(float input){
String inputAsString = Float.toString(input);
System.out.println(inputAsString);
int digits = 0;
// go to less than 2 because first 2 will be 0 and .
for(int i =0;i<inputAsString.length()-2;i++){
digits++;
}
return digits;
}

我的测试方法如下所示:

@Test
public void testConvertDecimalPartToString(){
float input = 0.95f;
//output is 94/100 and assert fails
Assert.assertEquals("95/100", checkWriter.convertDecimalPartToString(input));
}

这一行似乎有误判:String numerator = Integer.toString((int) (input * Math.pow(10, numberOfDigits)));但我不明白为什么它对0.05, 0.15, 0.25, 0.55, 0.75 and 0.85有效.

谁能帮我理解?

问题是祝福的数字。想象一下,我给了你 3 位(0 或 1 个值):你只能用这个表示 8 个不同的值:000、001、010、011、100、101、110 和 111。这就是他们的全部。如果这是唯一的合法值,则不能代表超过 8 个概念!

float是一个 32 位值。使用32位,我可以为您提供多达40亿个不同的值。这是很多值,但它不是无限的,但是在 0 和 1 之间有无限的数字,更不用说 0 到340,282,346,638,528,860,000,000,000,000,000,000,000.000000之间了,这是float可以表示的最大值。

那么这是如何工作的呢?好吧,并非每个数字实际上都是可表示的。只有大约40亿个数字。这些是有福的数字。

每当您尝试制作一个非祝福数字,或者计算结果没有祝福时,您的数字都会四舍五入到最接近的祝福数字,如果您执行一系列操作,则每一步都会发生舍入。

祝福数字的本质是,10 和 1 的祝福数字与 1 以上的祝福数字一样多 - 当你远离 0 时,任何 2 个祝福数字之间的间隔就会上升。事实上,最终它将超过1.0。

此外,计算机以二进制而不是十进制计数。就像你不能用十进制表示"1 除以 3 件事"(0.33333......它永远不会结束),像 0.1 这样简单的东西(1 除以 10 件事)不能用二进制完美地表示,所以像1.0/10.0这样简单的东西已经四舍五入了!

如果发生_any_rounding,代码将失败。在您的情况下,解决方案相当容易;添加 0.005 就可以了。更好的方法是首先将其呈现为舍入字符串:

String x = String.format("%.02f", yourValue);

然后在字符串中找到所需的内容。以上负责正确的舍入,并且会比使用 Math.pow 做得更好,当它使您远离 0 时,会导致出现更多错误(从 0>更极端的舍入误差,因为到目前为止的祝福数字更少)。

注意:请注意,double和浮点数一样快,考虑到你有 64 位可以在那里花费,有更多的祝福数字,所以,错误更少。

NB2:另一种方法是移动你的"单位"概念。例如,如果这代表现金,只需int cents;- 没有问题,知道int的祝福数字是什么(-2^31 和 +2^31 之间的每个整数)要容易得多。

相关内容

最新更新