¿Cómo obtener la parte decimal de un flotador?

Necesito extraer la parte decimal de un número flotante, pero obtengo resultados extraños:

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 

¿Por qué pasó esto? ¿Por qué obtengo esos valores en lugar de 0.65 ?

float solo tiene unos pocos dígitos de precisión, por lo que deberías esperar ver un error de ronda con bastante facilidad. intenta double esto tiene más precisión pero aún tiene errores de redondeo. Tienes que redondear cualquier respuesta para tener una salida sana.

Si esto no es deseable puede usar BigDecimal que no tiene errores de redondeo, pero tiene sus propios dolores de cabeza en mi humilde opinión.

EDITAR: Puede encontrar esto interesante. El Float.toString () predeterminado usa un redondeo mínimo, pero a menudo no es suficiente.

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

Huellas dactilares

 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 

Creo que esta sería la forma más simple:

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

Porque no todos los números racionales se pueden representar como un número de coma flotante y 0.6499996... es la aproximación más aproximada para 0.65 .

Por ejemplo, intente imprimir los primeros 20 dígitos del número 0.65 :

  System.out.printf("%.20f\n", 0.65f); 

->

  0.64999997615814210000 

editar
Los errores de redondeo, que se acumulan durante los cálculos, también juegan un papel en él, como otros señalaron.

Mordí largo pero funciona:

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

Si solo desea imprimir el número a 2dp, puede usar DecimalFormat.

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

Si quieres números de puntos fijos internamente usa BigDecimal

Respuesta corta: no puede representar algunos números exactamente en binario que son “exactos” en decimal.

Respuesta larga: http://www-users.math.umd.edu/~jkolesar/mait613/floating_point_math.pdf

[Editar]

También una lectura interesante: http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf

El sonido y la forma perfecta de obtener la parte decimal de los tipos de datos float y double, se usa con String como este código:

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

Prueba esto. Si el temporizador es 10.65 , h termina como los dos primeros lugares decimales * 100 = 65.

Esta es una forma rápida y fácil de separar lo que desea sin los problemas de redondeo.

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

Prueba java.math.BigDecimal .

Este código funcionará para cualquier cantidad de dígitos decimales.

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