Лучший способ представить дробь в Java? - PullRequest
95 голосов
/ 24 января 2009

Я пытаюсь работать с фракциями в Java.

Я хочу реализовать арифметические функции. Для этого мне сначала потребуется способ нормализовать функции. Я знаю, что не могу добавить 1/6 и 1/2, пока у меня не будет общего знаменателя. Я должен буду добавить 1/6 и 3/6. Наивный подход заставил бы меня добавить 2/12 и 6/12, а затем уменьшить. Как мне достичь общего знаменателя с наименьшими потерями в производительности? Какой алгоритм лучше для этого?


Версия 8 (спасибо hstoerr ):

Улучшения включают в себя:

  • метод equals () теперь совместим с методом compareTo ()
final class Fraction extends Number {
    private int numerator;
    private int denominator;

    public Fraction(int numerator, int denominator) {
        if(denominator == 0) {
            throw new IllegalArgumentException("denominator is zero");
        }
        if(denominator < 0) {
            numerator *= -1;
            denominator *= -1;
        }
        this.numerator = numerator;
        this.denominator = denominator;
    }

    public Fraction(int numerator) {
        this.numerator = numerator;
        this.denominator = 1;
    }

    public int getNumerator() {
        return this.numerator;
    }

    public int getDenominator() {
        return this.denominator;
    }

    public byte byteValue() {
        return (byte) this.doubleValue();
    }

    public double doubleValue() {
        return ((double) numerator)/((double) denominator);
    }

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

    public int intValue() {
        return (int) this.doubleValue();
    }

    public long longValue() {
        return (long) this.doubleValue();
    }

    public short shortValue() {
        return (short) this.doubleValue();
    }

    public boolean equals(Fraction frac) {
        return this.compareTo(frac) == 0;
    }

    public int compareTo(Fraction frac) {
        long t = this.getNumerator() * frac.getDenominator();
        long f = frac.getNumerator() * this.getDenominator();
        int result = 0;
        if(t>f) {
            result = 1;
        }
        else if(f>t) {
            result = -1;
        }
        return result;
    }
}

Я удалил все предыдущие версии. Моя благодарность:

Ответы [ 26 ]

0 голосов
/ 05 февраля 2019

Фракция класса:

     public class Fraction {
        private int num;            // numerator 
        private int denom;          // denominator 
        // default constructor
        public Fraction() {}
        // constructor
        public Fraction( int a, int b ) {
            num = a;
            if ( b == 0 )
                throw new ZeroDenomException();
            else
                denom = b;
        }
        // return string representation of ComplexNumber
        @Override
        public String toString() {
            return "( " + num + " / " + denom + " )";
        }
        // the addition operation
        public Fraction add(Fraction x){
            return new Fraction(
                    x.num * denom + x.denom * num, x.denom * denom );
        }
        // the multiplication operation
        public Fraction multiply(Fraction x) {
            return new Fraction(x.num * num, x.denom * denom);
        } 
}

Основная программа:

    static void main(String[] args){
    Scanner input = new Scanner(System.in);
    System.out.println("Enter numerator and denominator of first fraction");
    int num1 =input.nextInt();
    int denom1 =input.nextInt();
    Fraction x = new Fraction(num1, denom1);
    System.out.println("Enter numerator and denominator of second fraction");
    int num2 =input.nextInt();
    int denom2 =input.nextInt();
    Fraction y = new Fraction(num2, denom2);
    Fraction result = new Fraction();
    System.out.println("Enter required operation: A (Add), M (Multiply)");
    char op = input.next().charAt(0);
    if(op == 'A') {
        result = x.add(y);
        System.out.println(x + " + " + y + " = " + result);
    }
0 голосов
/ 07 января 2016

Для отраслевой реализации Fraction / Rational я бы реализовал ее так, чтобы она могла представлять NaN, положительную бесконечность, отрицательную бесконечность и, возможно, отрицательный ноль с операционной семантикой, точно такой же, как у стандартных состояний IEEE 754 для арифметики с плавающей запятой (это также облегчает преобразование в / из значений с плавающей запятой). Кроме того, поскольку сравнение с нулем, одному и специальным значениям, приведенным выше, требует только простого, но комбинированное сравнение числителя и знаменателя с 0 и 1 - я бы добавил несколько методов isXXX и compareToXXX для простоты использования (например, eq0 () используйте числитель == 0 && denominator! = 0 за кулисами вместо того, чтобы позволить клиенту сравнивать с экземпляром с нулевым значением). Некоторые статически предопределенные значения (ZERO, ONE, TWO, TEN, ONE_TENTH, NAN и т. Д.) Также полезны, так как они появляются в нескольких местах как постоянные значения. Это лучший способ ИМХО.

0 голосов
/ 21 марта 2015

Эта функция упрощения с использованием алгоритма Евклида весьма полезна при определении дробей

 public Fraction simplify(){


     int safe;
     int h= Math.max(numerator, denominator);
     int h2 = Math.min(denominator, numerator);

     if (h == 0){

         return new Fraction(1,1);
     }

     while (h>h2 && h2>0){

          h = h - h2;
          if (h>h2){

              safe = h;
              h = h2;
              h2 = safe;

          }  

     }

  return new Fraction(numerator/h,denominator/h);

 }
0 голосов
/ 26 апреля 2013

Даже если у вас есть методы compareTo (), если вы хотите использовать такие утилиты, как Collections.sort (), вам также следует реализовать Comparable.

public class Fraction extends Number implements Comparable<Fraction> {
 ...
}

Кроме того, для красивого отображения я рекомендую переопределить toString ()

public String toString() {
    return this.getNumerator() + "/" + this.getDenominator();
}

И, наконец, я сделаю класс общедоступным, чтобы вы могли использовать его из разных пакетов.

0 голосов
/ 28 октября 2012

Может быть полезно добавить простые вещи, такие как взаимность, получить остаток и получить целое.

0 голосов
/ 24 января 2009

Начальное замечание:

Никогда не пиши это:

if ( condition ) statement;

Это намного лучше

if ( condition ) { statement };

Просто создай, чтобы создать хорошую привычку.

Сделав класс неизменным, как предложено, вы также можете воспользоваться преимуществом double для выполнения операций equals и hashCode и compareTo

Вот моя быстрая грязная версия:

public final class Fraction implements Comparable {

    private final int numerator;
    private final int denominator;
    private final Double internal;

    public static Fraction createFraction( int numerator, int denominator ) { 
        return new Fraction( numerator, denominator );
    }

    private Fraction(int numerator, int denominator) {
        this.numerator   = numerator;
        this.denominator = denominator;
        this.internal = ((double) numerator)/((double) denominator);
    }


    public int getNumerator() {
        return this.numerator;
    }

    public int getDenominator() {
        return this.denominator;
    }


    private double doubleValue() {
        return internal;
    }

    public int compareTo( Object o ) {
        if ( o instanceof Fraction ) { 
            return internal.compareTo( ((Fraction)o).internal );
        }
        return 1;
    }

    public boolean equals( Object o ) {
          if ( o instanceof Fraction ) {  
             return this.internal.equals( ((Fraction)o).internal );
          } 
          return false;
    }

    public int hashCode() { 
        return internal.hashCode();
    }



    public String toString() { 
        return String.format("%d/%d", numerator, denominator );
    }

    public static void main( String [] args ) { 
        System.out.println( Fraction.createFraction( 1 , 2 ) ) ;
        System.out.println( Fraction.createFraction( 1 , 2 ).hashCode() ) ;
        System.out.println( Fraction.createFraction( 1 , 2 ).compareTo( Fraction.createFraction(2,4) ) ) ;
        System.out.println( Fraction.createFraction( 1 , 2 ).equals( Fraction.createFraction(4,8) ) ) ;
        System.out.println( Fraction.createFraction( 3 , 9 ).equals( Fraction.createFraction(1,3) ) ) ;
    }       

}

Что касается статического метода фабрики, он может быть полезен позже, если вы создадите подкласс Fraction для обработки более сложных вещей или если вы решите использовать пул для наиболее часто используемых объектов.

Возможно, дело не в этом, я просто хотел указать на это. :)

См. Эффективная Java Первый элемент.

...