Fractions en Java

Rashmi Patidar 12 octobre 2023
Fractions en Java

Mathématiquement, les fractions sont les parties ou sections de valeurs. Lorsqu’un objet est brisé également dans des proportions définies, la valeur formée s’appelle une fraction. Les fractions sont classées en nombres rationnels et irrationnels.

Dans le langage de programmation Java, il existe un privilège d’effectuer diverses opérations sur des fractions telles que des procédures mathématiques. On peut additionner, soustraire, multiplier et diviser sur les nombres fractionnaires.

Vous trouverez ci-dessous le bloc de code qui illustre les opérations de nombre rationnel dans la classe définie par l’utilisateur.

import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RationalNumber {
  public final static RationalNumber ZERO = new RationalNumber(BigInteger.ZERO, BigInteger.ONE);

  private final BigInteger numerator, denominator;

  private RationalNumber(BigInteger numerator, BigInteger denominator) {
    this.numerator = numerator;
    this.denominator = denominator;
  }

  private static RationalNumber canonical(
      BigInteger numerator, BigInteger denominator, boolean checkGcd) {
    if (denominator.signum() == 0) {
      throw new IllegalArgumentException("denominator is zero");
    }
    if (numerator.signum() == 0) {
      return ZERO;
    }
    if (denominator.signum() < 0) {
      numerator = numerator.negate();
      denominator = denominator.negate();
    }
    if (checkGcd) {
      BigInteger gcd = numerator.gcd(denominator);
      if (!gcd.equals(BigInteger.ONE)) {
        numerator = numerator.divide(gcd);
        denominator = denominator.divide(gcd);
      }
    }
    return new RationalNumber(numerator, denominator);
  }

  public static RationalNumber getInstance(long numerator, long denominator) {
    return canonical(new BigInteger("" + numerator), new BigInteger("" + denominator), true);
  }

  public static RationalNumber valueOf(String s) {
    Pattern p = Pattern.compile("(-?\\d+)(?:.(\\d+)?)?0*(?:e(-?\\d+))?");
    Matcher m = p.matcher(s);
    if (!m.matches()) {
      throw new IllegalArgumentException("Unknown format '" + s + "'");
    }
    String whole = m.group(1);
    String decimal = m.group(2);
    String exponent = m.group(3);
    String n = whole;
    if (decimal != null) {
      n += decimal;
    }
    BigInteger numerator = new BigInteger(n);
    int exp = exponent == null ? 0 : Integer.valueOf(exponent);
    int decimalPlaces = decimal == null ? 0 : decimal.length();
    exp -= decimalPlaces;
    BigInteger denominator;
    if (exp < 0) {
      denominator = BigInteger.TEN.pow(-exp);
    } else {
      numerator = numerator.multiply(BigInteger.TEN.pow(exp));
      denominator = BigInteger.ONE;
    }

    return canonical(numerator, denominator, true);
  }

  public static void main(String[] args) {
    RationalNumber r1 = RationalNumber.valueOf("3.14e4");
    RationalNumber r2 = RationalNumber.getInstance(111, 7);
    convert("r1", r1);
    convert("r2", r2);
    convert("r1 + r2", r1.add(r2));
    convert("r1 - r2", r1.subtract(r2));
    convert("r1 * r2", r1.multiply(r2));
    convert("r1 / r2", r1.divide(r2));
    convert("r2 ^ 2", r2.pow(2));
  }

  public static void convert(String name, RationalNumber r) {
    System.out.printf("%s = %s%n", name, r);
    System.out.printf("%s.negate() = %s%n", name, r.negate());
    System.out.printf("%s.invert() = %s%n", name, r.invert());
    System.out.printf("%s.intValue() = %,d%n", name, r.intValue());
    System.out.printf("%s.longValue() = %,d%n", name, r.longValue());
    System.out.printf("%s.floatValue() = %,f%n", name, r.floatValue());
    System.out.printf("%s.doubleValue() = %,f%n", name, r.doubleValue());
    System.out.println();
  }

  public RationalNumber add(RationalNumber o) {
    if (o.numerator.signum() == 0) {
      return this;
    } else if (numerator.signum() == 0) {
      return o;
    } else if (denominator.equals(o.denominator)) {
      return new RationalNumber(numerator.add(o.numerator), denominator);
    } else {
      return canonical(numerator.multiply(o.denominator).add(o.numerator.multiply(denominator)),
          denominator.multiply(o.denominator), true);
    }
  }

  public RationalNumber multiply(RationalNumber o) {
    if (numerator.signum() == 0 || o.numerator.signum() == 0) {
      return ZERO;
    } else if (numerator.equals(o.denominator)) {
      return canonical(o.numerator, denominator, true);
    } else if (o.numerator.equals(denominator)) {
      return canonical(numerator, o.denominator, true);
    } else if (numerator.negate().equals(o.denominator)) {
      return canonical(o.numerator.negate(), denominator, true);
    } else if (o.numerator.negate().equals(denominator)) {
      return canonical(numerator.negate(), o.denominator, true);
    } else {
      return canonical(numerator.multiply(o.numerator), denominator.multiply(o.denominator), true);
    }
  }

  public boolean isInteger() {
    return numerator.signum() == 0 || denominator.equals(BigInteger.ONE);
  }

  public RationalNumber negate() {
    return new RationalNumber(numerator.negate(), denominator);
  }

  public RationalNumber invert() {
    return canonical(denominator, numerator, false);
  }

  public RationalNumber pow(int exp) {
    return canonical(numerator.pow(exp), denominator.pow(exp), true);
  }

  public RationalNumber subtract(RationalNumber o) {
    return add(o.negate());
  }

  public RationalNumber divide(RationalNumber o) {
    return multiply(o.invert());
  }

  public int intValue() {
    return isInteger() ? numerator.intValue() : numerator.divide(denominator).intValue();
  }

  public long longValue() {
    return isInteger() ? numerator.longValue() : numerator.divide(denominator).longValue();
  }

  public float floatValue() {
    return (float) doubleValue();
  }

  public double doubleValue() {
    return isInteger() ? numerator.doubleValue()
                       : numerator.doubleValue() / denominator.doubleValue();
  }

  @Override
  public String toString() {
    return isInteger() ? String.format("%,d", numerator)
                       : String.format("%,d / %,d", numerator, denominator);
  }
}

Dans le programme ci-dessus, l’exécution démarre à partir de la méthode main. Tout d’abord, un nombre rationnel est initialisé à l’aide de la fonction statique valueOf() définie dans la classe. Il prend une valeur de chaîne et effectue des manipulations sur la chaîne d’entrée.

Il renvoie un RationalNumber du type défini par l’utilisateur. La fonction vérifie d’abord une chaîne d’entrée avec des validations et des modèles appropriés. La chaîne d’entrée est séparée en exposant, décimal et toute la partie. Ces valeurs brisées individuelles se combinent pour former un nombre rationnel.

Une autre façon de créer un nombre rationnel consiste à utiliser une fonction d’usine statique instanceOf(). La méthode appelle en interne la fonction canonical, qui appelle un constructeur privé de la classe. Le constructeur sépare et définit les valeurs du numérateur et du dénominateur pour une instance spécifique. Par forme canonique, on entend simplement la forme de représentation standard du nombre rationnel.

Dans le cas donné, p/q est la forme standard ou canonique où q!=0 devrait toujours être vrai. La méthode a la logique écrite pour satisfaire les conditions de base d’un nombre rationnel. Il vérifie séparément le signe du numérateur et du dénominateur et effectue des opérations. Il vérifie les valeurs du dénominateur ; si c’est zéro, l’opération lève une exception. Il vérifie également le plus grand commun diviseur ou pgcd dans les valeurs du numérateur et du dénominateur. La fonction gcd est présente dans la classe BigInteger qui renvoie une valeur BigInteger.

Pour aller de l’avant, la méthode convert est appelée, en passant la première instance de nombre rationnel qui est créée. Cette méthode fait également appel à sept fonctions différentes sur l’instance nombre rationnel qui est passée.

Ci-dessous, vous comprendrez mieux chacune de ces méthodes :

  • Imprimer le nombre rationnel dans le flux d’impression. Généralement, chaque fois qu’une instance est imprimée, la méthode par défaut toString est appelée. La méthode imprime le nom de la classe suivi de la représentation hexadécimale de l’emplacement mémoire. Mais ici, la fonction est surchargée pour donner une autre implémentation qui représente le nombre sous la forme p/q.
  • La fonction negate niera en interne le nombre rationnel en appelant la méthode negate de la classe BigInteger. Il ajoutera un signe moins avant le nombre rationnel.
  • La fonction invert appelle en interne la méthode canonical avec une seule différence. Il passe en interne le troisième paramètre checkGcd comme false. Lorsque la valeur d’entrée est booléenne true, la logique de la méthode simplifie le nombre rationnel en divisant la fraction par son plus grand diviseur commun. Mais dans ce cas, il s’agit d’inverser sans simplification.
  • La fonction intValue vérifie d’abord si l’instance est une valeur Integer. Les Integers sont des nombres qui peuvent être positifs, négatifs ou nuls, mais ne peuvent pas être des fractions. Ainsi, en interne, il appelle la méthode divide sur le numérateur et le dénominateur. La méthode est donnée dans la classe BigInteger et retourne une valeur BigInteger. Il lève également ArithmeticException lorsque le dénominateur trouve une valeur zéro. La valeur renvoyée est transformée en une valeur int à l’aide de la fonction intValue.
  • La fonction longValue appelle en interne la fonction de division et parse la sortie BigInteger en un type de données long.
  • La fonction floatValue fournit la valeur à virgule flottante du nombre rationnel. Et de même que la fonction doubleValue(), qui transtype la sortie dans le type de données Double.

L’ensemble du processus est appelé sur une instance initiale de nombre rationnel qui est l’instance r1. Une séquence similaire est à nouveau répétée et est imprimée pour l’instance rationnelle r2.

Opérations mathématiques pour les fractions en Java

Maintenant, les opérations arithmétiques d’addition, de soustraction, de division, de multiplication et de puissance nécessitent deux opérandes pour l’évaluation. Examinons donc les méthodes en détail ci-dessous :

  1. La fonction add vérifie d’abord les valeurs du numérateur si elles sont positives, négatives ou nulles. S’il est différent de zéro, il vérifie si les dénominateurs des deux nombres rationnels sont les mêmes. S’il est identique, il ajoute la valeur du numérateur et renvoie le nombre rationnel formé. Sinon, s’il n’est pas trouvé similaire, il définit la logique pour l’addition rationnelle de nombres.
  2. La méthode subtract appelle en interne la méthode add après avoir nié la deuxième instance de nombre rationnel passée.
  3. La méthode multiply a une logique assez complexe en interne. Il vérifie si le numérateur est zéro de l’un des nombres rationnels, il renvoie la sortie sous forme de valeur zéro. Si ce n’est pas zéro, il vérifie le numérateur avec le dénominateur de l’un ou l’autre ensemble. C’est-à-dire que le numérateur r1 est vérifié avec le dénominateur r2 et vice-versa. Lorsqu’aucune condition ne correspond, le numérateur de r1 est multiplié par le numérateur d’instance r2, et les dénominateurs des deux sont multipliés. Enfin, il appelle la fonction multiply de la classe BigInteger pour effectuer la multiplication.
  4. La fonction divide inversera l’instance passée et appellera en interne la fonction multiply en utilisant la première instance.
  5. La dernière est la fonction pow qui évalue la seconde puissance de l’instance r2. L’implémentation de pow est définie dans la classe BigInteger qui prend l’exposant pour l’évaluation. La méthode lève l’exception ArithmeticException lorsque l’exposant est une valeur négative.

Vous trouverez ci-dessous la sortie du code complexe donné ci-dessus :

r1 = 31, 400 r1.negate() = -31, 400 r1.invert() = 1 / 31, 400 r1.intValue() = 31,
             400 r1.longValue() = 31, 400 r1.floatValue() = 31, 400.000000 r1.doubleValue() = 31,
             400.000000

    r2 = 111 / 7 r2.negate() = -111 / 7 r2.invert() = 7 / 111 r2.intValue() = 15 r2.longValue() =
        15 r2.floatValue() = 15.857142 r2.doubleValue() = 15.857143

    r1
    + r2 = 219,
             911 / 7 r1 + r2.negate() = -219, 911 / 7 r1 + r2.invert() = 7 / 219,
             911 r1 + r2.intValue() = 31, 415 r1 + r2.longValue() = 31,
             415 r1 + r2.floatValue() = 31, 415.857422 r1 + r2.doubleValue() = 31,
             415.857143

    r1
    - r2 = 219,
             689 / 7 r1 - r2.negate() = -219, 689 / 7 r1 - r2.invert() = 7 / 219,
             689 r1 - r2.intValue() = 31, 384 r1 - r2.longValue() = 31,
             384 r1 - r2.floatValue() = 31, 384.142578 r1 - r2.doubleValue() = 31,
             384.142857

    r1* r2 = 3,
             485, 400 / 7 r1* r2.negate() = -3, 485, 400 / 7 r1* r2.invert() = 7 / 3, 485,
             400 r1* r2.intValue() = 497, 914 r1* r2.longValue() = 497,
             914 r1* r2.floatValue() = 497, 914.281250 r1* r2.doubleValue() = 497,
             914.285714

    r1
    / r2 = 219,
             800 / 111 r1 / r2.negate() = -219, 800 / 111 r1 / r2.invert() = 111 / 219,
             800 r1 / r2.intValue() = 1, 980 r1 / r2.longValue() = 1, 980 r1 / r2.floatValue() = 1,
             980.180176 r1 / r2.doubleValue() = 1,
             980.180180

    r2
    ^ 2 = 12,
             321 / 49 r2 ^ 2.negate() = -12, 321 / 49 r2 ^ 2.invert() = 49 / 12,
             321 r2 ^ 2.intValue() = 251 r2 ^ 2.longValue() = 251 r2
    ^ 2.floatValue() = 251.448975 r2 ^ 2.doubleValue() = 251.448980
Rashmi Patidar avatar Rashmi Patidar avatar

Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.

LinkedIn

Article connexe - Java Math