I need to extract the decimal part of a float number, but I get weird results:
我需要提取浮点数的小数部分,但我得到奇怪的结果:
float n = 22.65f;
// I want x = 0.65f, but...
x = n % 1; // x = 0.6499996
x = n - Math.floor(n); // x = 0.6499996185302734
x = n - (int)n; // x = 0.6499996
Why does this happen? Why do I get those values instead of 0.65
?
为什么会这样?为什么我得到这些值而不是0.65?
10 个解决方案
#1
38
float
only has a few digit of precision so you should expect to see a round error fairly easily. try double
this has more accuracy but still has rounding errors. You have to round any answer you get to have a sane output.
float只有几位精度,所以你应该很容易看到一个圆形错误。尝试加倍,这具有更高的准确性,但仍然有舍入错误。你必须得到任何答案才能获得理智的输出。
If this is not desireable you can use BigDecimal which does not have rounding errors, but has its own headaches IMHO.
如果这不是你想要的,你可以使用BigDecimal,它没有舍入错误,但有自己的头痛恕我直言。
EDIT: You may find this interesting. The default Float.toString() uses minimal rounding, but often its not enough.
编辑:你可能会发现这很有趣。默认的Float.toString()使用最小的舍入,但通常是不够的。
System.out.println("With no rounding");
float n = 22.65f;
System.out.println("n= "+new BigDecimal(n));
float expected = 0.65f;
System.out.println("expected= "+new BigDecimal(expected));
System.out.println("n % 1= "+new BigDecimal(n % 1));
System.out.println("n - Math.floor(n) = "+new BigDecimal(n - Math.floor(n)));
System.out.println("n - (int)n= "+new BigDecimal(n - (int)n));
System.out.println("With rounding");
System.out.printf("n %% 1= %.2f%n", n % 1);
System.out.printf("n - Math.floor(n) = %.2f%n", n - Math.floor(n));
System.out.printf("n - (int)n= %.2f%n", n - (int)n);
Prints
打印
With no rounding
n= 22.6499996185302734375
expected= 0.64999997615814208984375
n % 1= 0.6499996185302734375
n - Math.floor(n) = 0.6499996185302734375
n - (int)n= 0.6499996185302734375
With rounding
n % 1= 0.65
n - Math.floor(n) = 0.65
n - (int)n= 0.65
#2
15
I think this would be the most simple way :
我认为这将是最简单的方法:
float n = 22.65f;
float x = n - (int) n;
#3
7
Because not all rational numbers can be represented as a floating point number and 0.6499996...
is the closest approximation for 0.65
.
因为并非所有有理数都可以表示为浮点数而且0.6499996 ...是0.65的最接近的近似值。
E.g., try printing first 20 digits of the number 0.65
:
例如,尝试打印数字0.65的前20位数字:
System.out.printf("%.20f\n", 0.65f);
->
- >
0.64999997615814210000
edit
Rounding errors, which accumulate during computations, also play a part in it, as others noted.
正如其他人所指出的那样,在计算过程中积累的舍入误差也会在其中起作用。
#4
6
I bit long but works:
我有点长,但工作:
BigDecimal.valueOf(2.65d).divideAndRemainder(BigDecimal.ONE)[1].floatValue()
#5
3
If you just want to print the number to 2dp you can use DecimalFormat.
如果您只想将数字打印到2dp,可以使用DecimalFormat。
DecimalFormat df= new DecimalFormat("#.##");
System.out.println(df.format(f));
If you want fixed point numbers internally use BigDecimal
如果你想在内部使用BigDecimal定点数
#6
2
Short answer: You can't represent some numbers exactly in binary that are "exact" in decimal.
简短回答:您不能完全用二进制表示一些十进制“精确”的数字。
Long answer: http://www-users.math.umd.edu/~jkolesar/mait613/floating_point_math.pdf
答案很长:http://www-users.math.umd.edu/~jkolesar/mait613/floating_point_math.pdf
[Edit]
[编辑]
Also an interesting read: http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf
另一个有趣的读物:http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf
#7
2
The sound and perfect way to get decimal part of float and double data types, is using with String like this code:
获取float和double数据类型的小数部分的声音和完美方法是使用String这样的代码:
float num=2.35f;
String s= new Float(num).toString();
String p=s.substring(s.indexOf('.')+1,s.length());
int decimal=Integer.parseInt(p);
#8
2
Try this. If timer is 10.65 then h ends up as the first two decimal places * 100 = 65.
尝试这个。如果计时器是10.65,那么h结束为前两位小数* 100 = 65。
This is a quick and easy way to separate what you want without the rounding issues.
这是一种快速简便的方法,可以在没有舍入问题的情况下分离您想要的内容。
float h = (int)((timer % 1) * 100);
#10
0
This code will work for any number of decimal digits.
此代码适用于任意数量的十进制数字。
float f = 2.3445f;
String s = Float.toString(f);
char[] c = s.toCharArray();
int length = s.length();
int flag = 0;
StringBuilder n = new StringBuilder();
for(int i = 0; i < length; i++)
{
if(flag == 1)
{
n.append(c[i]);
}
if(c[i] == '.')
{
flag = 1;
}
}
String result = n.toString();
int answer = Integer.parseInt(result);
System.out.println(answer);
#1
38
float
only has a few digit of precision so you should expect to see a round error fairly easily. try double
this has more accuracy but still has rounding errors. You have to round any answer you get to have a sane output.
float只有几位精度,所以你应该很容易看到一个圆形错误。尝试加倍,这具有更高的准确性,但仍然有舍入错误。你必须得到任何答案才能获得理智的输出。
If this is not desireable you can use BigDecimal which does not have rounding errors, but has its own headaches IMHO.
如果这不是你想要的,你可以使用BigDecimal,它没有舍入错误,但有自己的头痛恕我直言。
EDIT: You may find this interesting. The default Float.toString() uses minimal rounding, but often its not enough.
编辑:你可能会发现这很有趣。默认的Float.toString()使用最小的舍入,但通常是不够的。
System.out.println("With no rounding");
float n = 22.65f;
System.out.println("n= "+new BigDecimal(n));
float expected = 0.65f;
System.out.println("expected= "+new BigDecimal(expected));
System.out.println("n % 1= "+new BigDecimal(n % 1));
System.out.println("n - Math.floor(n) = "+new BigDecimal(n - Math.floor(n)));
System.out.println("n - (int)n= "+new BigDecimal(n - (int)n));
System.out.println("With rounding");
System.out.printf("n %% 1= %.2f%n", n % 1);
System.out.printf("n - Math.floor(n) = %.2f%n", n - Math.floor(n));
System.out.printf("n - (int)n= %.2f%n", n - (int)n);
Prints
打印
With no rounding
n= 22.6499996185302734375
expected= 0.64999997615814208984375
n % 1= 0.6499996185302734375
n - Math.floor(n) = 0.6499996185302734375
n - (int)n= 0.6499996185302734375
With rounding
n % 1= 0.65
n - Math.floor(n) = 0.65
n - (int)n= 0.65
#2
15
I think this would be the most simple way :
我认为这将是最简单的方法:
float n = 22.65f;
float x = n - (int) n;
#3
7
Because not all rational numbers can be represented as a floating point number and 0.6499996...
is the closest approximation for 0.65
.
因为并非所有有理数都可以表示为浮点数而且0.6499996 ...是0.65的最接近的近似值。
E.g., try printing first 20 digits of the number 0.65
:
例如,尝试打印数字0.65的前20位数字:
System.out.printf("%.20f\n", 0.65f);
->
- >
0.64999997615814210000
edit
Rounding errors, which accumulate during computations, also play a part in it, as others noted.
正如其他人所指出的那样,在计算过程中积累的舍入误差也会在其中起作用。
#4
6
I bit long but works:
我有点长,但工作:
BigDecimal.valueOf(2.65d).divideAndRemainder(BigDecimal.ONE)[1].floatValue()
#5
3
If you just want to print the number to 2dp you can use DecimalFormat.
如果您只想将数字打印到2dp,可以使用DecimalFormat。
DecimalFormat df= new DecimalFormat("#.##");
System.out.println(df.format(f));
If you want fixed point numbers internally use BigDecimal
如果你想在内部使用BigDecimal定点数
#6
2
Short answer: You can't represent some numbers exactly in binary that are "exact" in decimal.
简短回答:您不能完全用二进制表示一些十进制“精确”的数字。
Long answer: http://www-users.math.umd.edu/~jkolesar/mait613/floating_point_math.pdf
答案很长:http://www-users.math.umd.edu/~jkolesar/mait613/floating_point_math.pdf
[Edit]
[编辑]
Also an interesting read: http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf
另一个有趣的读物:http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf
#7
2
The sound and perfect way to get decimal part of float and double data types, is using with String like this code:
获取float和double数据类型的小数部分的声音和完美方法是使用String这样的代码:
float num=2.35f;
String s= new Float(num).toString();
String p=s.substring(s.indexOf('.')+1,s.length());
int decimal=Integer.parseInt(p);
#8
2
Try this. If timer is 10.65 then h ends up as the first two decimal places * 100 = 65.
尝试这个。如果计时器是10.65,那么h结束为前两位小数* 100 = 65。
This is a quick and easy way to separate what you want without the rounding issues.
这是一种快速简便的方法,可以在没有舍入问题的情况下分离您想要的内容。
float h = (int)((timer % 1) * 100);
#9
#10
0
This code will work for any number of decimal digits.
此代码适用于任意数量的十进制数字。
float f = 2.3445f;
String s = Float.toString(f);
char[] c = s.toCharArray();
int length = s.length();
int flag = 0;
StringBuilder n = new StringBuilder();
for(int i = 0; i < length; i++)
{
if(flag == 1)
{
n.append(c[i]);
}
if(c[i] == '.')
{
flag = 1;
}
}
String result = n.toString();
int answer = Integer.parseInt(result);
System.out.println(answer);