Maison >Java >javaDidacticiel >Pourquoi la double perd la précision et comment l'éviter à Java

Pourquoi la double perd la précision et comment l'éviter à Java

Patricia Arquette
Patricia Arquetteoriginal
2025-01-27 18:09:10939parcourir

Why double Loses Precision and How to Avoid It in Java

Lorsque vous travaillez avec des nombres à virgule flottante en Java, vous remarquerez peut-être que double produit parfois des résultats inattendus ou imprécis. Ce comportement peut conduire à des erreurs, en particulier dans les applications ou scénarios financiers qui nécessitent une grande précision.

Dans cet article, nous examinerons la cause profonde de ce problème, expliquerons comment l'éviter, fournirons un exemple concret et explorerons si les versions Java plus récentes offrent de meilleures alternatives.

Pourquoi le double perd-il en précision ?

1. Norme à virgule flottante IEEE 754

Le type de données double en Java suit la norme de fonctionnement des nombres à virgule flottante IEEE 754. Il représente les nombres au format binaire en utilisant :

  • 1 bit est utilisé pour les symboles,
  • 11 bits pour l'exposant,
  • 52 bits sont utilisés pour les fractions (mantisse).

Cette représentation binaire introduit des limitations :

  • Précision limitée : le double ne peut représenter avec précision que jusqu'à 15 à 17 chiffres décimaux.
  • Erreur d'arrondi : De nombreuses fractions décimales (par exemple, 0,1) ne peuvent pas être représentées exactement sous forme de nombres binaires, ce qui entraîne des erreurs d'arrondi.

Par exemple, en binaire :

  • 0,1 devient une décimale infiniment récurrente qui est tronquée pour le stockage, introduisant ainsi de légères inexactitudes.

2. Erreur cumulative dans les opérations arithmétiques

Les opérations impliquant un double peuvent accumuler des erreurs :

  • Les ajouts/soustractions répétés amplifient les erreurs d’arrondi.
  • La multiplication/division peut perdre en précision en raison de la troncature.

Ce comportement est inhérent à l'arithmétique à virgule flottante et n'est pas propre à Java.


Exemple réalisable : perte de précision causée par l'utilisation du double

Voici un exemple illustrant le problème :

<code class="language-java">public class DoublePrecisionLoss {
    public static void main(String[] args) {
        double num1 = 0.1;
        double num2 = 0.2;
        double sum = num1 + num2;

        System.out.println("预期和:0.3");
        System.out.println("实际和:" + sum);

        // 比较
        if (sum == 0.3) {
            System.out.println("和等于0.3");
        } else {
            System.out.println("和不等于0.3");
        }
    }
}</code>

Sortie :

<code>预期和:0.3
实际和:0.30000000000000004
和不等于0.3</code>

Le résultat 0,30000000000000004 met en évidence l'erreur d'arrondi provoquée par la représentation binaire. Même des différences insignifiantes peuvent entraîner des problèmes majeurs dans les systèmes critiques.


Comment éviter la perte de précision

1. Utilisez BigDecimal pour des calculs précis

La classe BigDecimal en Java fournit une arithmétique de précision arbitraire, ce qui la rend idéale pour les scénarios nécessitant une haute précision (tels que les calculs financiers).

Exemple utilisant BigDecimal :

<code class="language-java">import java.math.BigDecimal;

public class BigDecimalExample {
    public static void main(String[] args) {
        BigDecimal num1 = new BigDecimal("0.1");
        BigDecimal num2 = new BigDecimal("0.2");
        BigDecimal sum = num1.add(num2);

        System.out.println("预期和:0.3");
        System.out.println("实际和:" + sum);

        // 比较
        if (sum.compareTo(new BigDecimal("0.3")) == 0) {
            System.out.println("和等于0.3");
        } else {
            System.out.println("和不等于0.3");
        }
    }
}</code>

Sortie :

<code>预期和:0.3
实际和:0.3
和等于0.3</code>

En utilisant BigDecimal, les problèmes de précision sont éliminés et les comparaisons produisent des résultats corrects.

2. Utilisez la valeur Epsilon pour comparaison

Une autre façon de gérer la perte de précision est de comparer les nombres à virgule flottante avec une tolérance (epsilon). Cette méthode vérifie si les nombres sont « suffisamment proches » plutôt que de s’appuyer sur une égalité exacte.

Exemple utilisant la comparaison Epsilon :

<code class="language-java">public class EpsilonComparison {
    public static void main(String[] args) {
        double num1 = 0.1;
        double num2 = 0.2;
        double sum = num1 + num2;
        double epsilon = 1e-9; // 定义一个小的容差值

        System.out.println("预期和:0.3");
        System.out.println("实际和:" + sum);

        // 使用epsilon进行比较
        if (Math.abs(sum - 0.3) < epsilon) {
            System.out.println("和大约等于0.3");
        } else {
            System.out.println("和不等于0.3");
        }
    }
}</code>

Sortie :

<code class="language-java">public class DoublePrecisionLoss {
    public static void main(String[] args) {
        double num1 = 0.1;
        double num2 = 0.2;
        double sum = num1 + num2;

        System.out.println("预期和:0.3");
        System.out.println("实际和:" + sum);

        // 比较
        if (sum == 0.3) {
            System.out.println("和等于0.3");
        } else {
            System.out.println("和不等于0.3");
        }
    }
}</code>

Pourquoi utiliser Epsilon pour comparer?

  • Flexibilité : Il permet de petites différences causées par l'erreur d'incorporation.
  • Simple
  • : Cette méthode ne nécessite pas de bibliothèques externes et l'efficacité est élevée.
Utilisez les mathématiques Apache Commons pour améliorer la précision

Apache Commons Math est une bibliothèque conçue pour l'informatique mathématique complexe. Bien qu'il ne fournit pas une précision arbitraire arithmétique comme BigDecimal, il fournit des procédures pratiques qui simplifient les opérations numériques et minimisent les erreurs de point flottantes dans certains cas.

Exemple: utilisez la précision.equals pour comparer

Sortie:
<code>预期和:0.3
实际和:0.30000000000000004
和不等于0.3</code>

Pourquoi utiliser les mathématiques Apache Commons?

<code class="language-java">import java.math.BigDecimal;

public class BigDecimalExample {
    public static void main(String[] args) {
        BigDecimal num1 = new BigDecimal("0.1");
        BigDecimal num2 = new BigDecimal("0.2");
        BigDecimal sum = num1.add(num2);

        System.out.println("预期和:0.3");
        System.out.println("实际和:" + sum);

        // 比较
        if (sum.compareTo(new BigDecimal("0.3")) == 0) {
            System.out.println("和等于0.3");
        } else {
            System.out.println("和不等于0.3");
        }
    }
}</code>

Comparaison simplifiée

: Precision.Equals permet l'utilisation de tolérants spécifiés pour comparer avec la tolérance spécifiée, afin de gérer facilement l'erreur d'incorporation.
  • Lightweight : La bibliothèque fournit des outils qui se concentrent sur les calculs numériques sans augmenter les dépenses de BigDecimal.
  • Résumé
  • Comprendre la limitation
: le double lui-même n'est pas défectueux, mais parce que sa représentation des points flottants binaires, il ne convient pas aux tâches à forte prorécision.

BigDecimal

: BigDecimal peut garantir la précision, mais peut affecter les performances des calculs financiers ou critiques.
  • Utilisation de la bibliothèque : Apache Commons Math fournit des programmes pratiques tels que Precision.Equals, qui peuvent gérer efficacement la comparaison de points flottants.
  • En comprenant Double et ses alternatives, vous pouvez écrire des applications Java plus robustes et plus précises.
  • Si vous rencontrez la précision du double et comment résoudre ces problèmes, dites-moi dans les commentaires! ?

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn