web-dev-qa-db-fra.com

Comment obtenir la partie décimale d'un float?

Je dois extraire la partie décimale d'un nombre flottant, mais j'obtiens des résultats étranges:

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

Pourquoi cela arrive-t-il? Pourquoi ai-je ces valeurs au lieu de 0.65?

42
Cristian

float n’a que quelques chiffres de précision, vous devriez donc vous attendre à voir une erreur d’arrondi assez facilement. try double ceci a plus de précision mais a encore des erreurs d'arrondi. Vous devez arrondir toute réponse pour obtenir une sortie saine.

Si cela n’est pas souhaitable, vous pouvez utiliser BigDecimal qui ne présente pas d’erreurs d’arrondi, mais a ses propres maux de tête, à mon humble avis.

EDIT: Vous pouvez trouver cela intéressant. La valeur par défaut Float.toString () utilise un arrondi minimal, mais souvent insuffisant.

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

Impressions

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
39
Peter Lawrey

Je pense que ce serait le moyen le plus simple:

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

Parce que tous les nombres rationnels ne peuvent pas être représentés comme un nombre à virgule flottante et que 0.6499996... est l’approximation la plus proche de 0.65

Par exemple, essayez d’imprimer les 20 premiers chiffres du numéro 0.65:

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

->

 0.64999997615814210000

modifier
Les erreurs d’arrondi, qui s’accumulent lors des calculs, y jouent également un rôle, comme d’autres l’ont noté.

7
Nikita Rybak

J'ai un peu long mais ça marche:

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

Si vous voulez seulement imprimer le nombre sur 2dp, vous pouvez utiliser DecimalFormat.

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

Si vous voulez des nombres de points fixes en interne, utilisez BigDecimal

3
ashbyp

Essayez ceci . Si timer est 10.65, alors h se termine sous les deux premières décimales * 100 = 65.

C'est un moyen rapide et facile de séparer ce que vous voulez sans les problèmes d'arrondi.

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

Réponse courte: Vous ne pouvez pas représenter des nombres exactement en binaire qui sont "exacts" en décimal.

Réponse longue: http://www-users.math.umd.edu/~jkolesar/mait613/floating_point_math.pdf

[Modifier]

Également une lecture intéressante: http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf

2
Landei

Le moyen idéal pour obtenir une partie décimale des types de données float et double consiste à utiliser String avec le code suivant: 

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

Ce code fonctionnera pour n’importe quel nombre de chiffres décimaux.

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);
0
Anand Kumar