开发者

How to get the decimal part of a float?

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?


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.

If this is not desireable you can use BigDecimal which does not have rounding errors, but has its own headaches IMHO.

EDIT: You may find this interesting. The default Float.toString() uses minimal rounding, but often its not enough.

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


I think this would be the most simple way :

float n = 22.65f;
float x = n - (int) n;


I bit long but works:

BigDecimal.valueOf(2.65d).divideAndRemainder(BigDecimal.ONE)[1].floatValue()


Because not all rational numbers can be represented as a floating point number and 0.6499996... is the closest approximation for 0.65.

E.g., try printing first 20 digits of the number 0.65:

 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.


The sound and perfect way to get decimal part of float and double data types, is using with String like this code:

float num=2.35f;
String s= new Float(num).toString();
String p=s.substring(s.indexOf('.')+1,s.length());
int decimal=Integer.parseInt(p);


Try this. If timer is 10.65 then h ends up as the first two decimal places * 100 = 65.

This is a quick and easy way to separate what you want without the rounding issues.

float h = (int)((timer % 1) * 100);


If you just want to print the number to 2dp you can use DecimalFormat.

DecimalFormat df= new DecimalFormat("#.##");
System.out.println(df.format(f));

If you want fixed point numbers internally use BigDecimal


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

[Edit]

Also an interesting read: http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf


Try java.math.BigDecimal.


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);


What about (Kotlin way):

val a = 1.1234
val dec = a - a.toInt()
val decimals = dec * 10f.pow(dec.toString().length - 2)

Take decimals and use/transform it as you want.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜