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
?
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
Je pense que ce serait le moyen le plus simple:
float n = 22.65f;
float x = n - (int) n;
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é.
J'ai un peu long mais ça marche:
BigDecimal.valueOf(2.65d).divideAndRemainder(BigDecimal.ONE)[1].floatValue()
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
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);
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
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);
Essayez Java.math.BigDecimal
.
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);