2014-02-05 4 views
3

Это мой класс Фракции код с несколькими методами, требование у меня есть, чтобы сохранить числитель в знаменатель как int:Как я могу отрицать Java фракцию, класс, который я создал

/** 
* @author GKsiazek 
* Reference: https://github.com/kiprobinson/BigFraction/blob/master/com/github/kiprobinson/util/BigFraction.java 
* Reference: https://github.com/kiprobinson/BigFraction/blob/master/com/github/kiprobinson/junit/BigFractionTest.java 
*/ 
package Fraction; 
import java.math.*; 
public class Fraction { 

    private int numerator; 
    private int denominator; 


    /** 
    * Constructor with two int parameters 
    * @param num is numerator 
    * @param den is denominator 
    */ 
    public Fraction() 
    {} 

    public Fraction(int num, int den) { 
     if (den==0){//denominator cannot be zero 
      System.out.println("Denominator cannot be zero"); 
      return; 
      } 
     this.numerator = num; 
     this.denominator = den; 
     this.normalize(); 
    } 

    /** 
    * Constructor with one int parameter 
    * @param num is numerator 
    * @param den is assumed one 
    */ 

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

    /** 
    * Constructor with String parameter 
    * @param str 
    * Only String in a following format "numerator/denominator" allowed 
    * If the String consists of one int it is considered denominator 
    * Numerator will be considered 1 
    * Denominator cannot be zero 
    */ 

    public Fraction(String str) 
    { 
     if(str.isEmpty()) 
     { 
      System.out.println("The str (String) parameter cannot be empty!"); 
     return; 
     } 

      String[] data = str.split("/"); 
      if(data.length==0) 
       System.out.println("The str (String) parameter cannot be empty"); 
      try 
      { 
       this.numerator = Integer.parseInt(data[0]); 
      } 
      catch (Exception ex) 
      { 
       System.out.println(ex.toString()); 
      } 
      try 
      { 

       this.denominator = Integer.parseInt(data[1]); 
       if(this.denominator==0) throw new Exception("Denominator can't be 0"); 
      } 
      catch (Exception ex) 
      { 
       System.out.println(ex.toString()); 
      } 
      this.normalize(); 
    } 



    /** 
    * the method is applied within the constructors 
    * normalize method takes care of fraction normalization 
    * 1.Converts the numerator and denominator into BigInteger 
    * 2.Finds the GCD of both 
    * 3.if the GCD is larger than 1 it divides numerator and denominator by GCD 
    * @param numerator 
    * @param denominator 
    */ 
    private void normalize()//int numerator, int denominator) 
    { 
     BigInteger gcd; 
     BigInteger num = BigInteger.valueOf(this.numerator); 
     BigInteger den = BigInteger.valueOf(this.denominator); 
     gcd = num.gcd(den); 
     if (gcd.intValue() > 1) 
     { 
      this.numerator = numerator/gcd.intValue(); 
      this.denominator = denominator/gcd.intValue(); 
     } 
    } 
    public Fraction abs() { 
     return null; 
    } 
    public int getNumerator() 
    { 
     return this.numerator; 
    } 

    public int getDenominator() 
    { 
     return this.denominator; 
    } 
    /* 
    * a/b + c/d is (ad + bc)/bd 
    */ 
    public Fraction add(Fraction g) 
    { 

     int numerator = this.numerator * g.denominator + this.denominator * g.numerator; 
     int denominator = this.denominator * g.denominator; 

     return new Fraction(numerator,denominator); 
    } 
    /** 
    * subtract method 
    * a/b - c/d is (ad - bc)/bd 
    * calls the normalize method to make sure that the Fraction h 
    * is in the normalized form 
    */ 

    public Fraction substract (Fraction g) 
    { 

     int num = this.numerator * g.denominator - this.denominator * g.numerator; 
     int den = this.denominator*g.denominator; 
     return new Fraction(num,den); 
    } 
    /** 
    * equals method 
    * public boolean equals(Object o) 
    */ 
    public boolean equals (Object o){ 
     if(o == null)return false; 
     return o.equals(this); 

    } 
    /** 
    * Multiplication 
    * (a/b) * (c/d) is (a*c)/(b*d) 
    * @param g 
    * @return 
    */ 
    public Fraction multiply(Fraction g) 
    { 
     int num = this.numerator * g.numerator; 
     int den = this.denominator * g.denominator; 
     return new Fraction(num,den); 
    } 
    /** 
    * Division 
    * (a/b)/(c/d) is (a*d)/(b*c) 
    * @param g 
    * @return 
    */ 
    public Fraction divide(Fraction g) 
    { 
     int num = this.numerator * g.denominator; 
     int den = this.denominator * g.numerator; 
     return new Fraction(num,den); 

    } 
    /** 
    * Negation 
    * -(a/b) is -a/b 
    */ 
    public Fraction negate() 
    { 
     int num = Math.abs(this.numerator) * -1; 
     int den = this.denominator; 
     return new Fraction(num,den); 
    } 
    /** 
    * Inverse of a/b is b/a 
    */ 
    public Fraction inverse() 
    { 
     int num = this.denominator; 
     int den = this.numerator; 
     return new Fraction(num,den); 
    } 
    /** 
    * a/b > c/d if ad > bc 
    * @return 
    */ 
    public boolean greaterThan(Fraction g) 
    { 
     if(this.numerator * g.denominator > this.denominator * g.numerator) 
     { 
      return true;//use the subtract() but how to 
     } 
     else return false; 
    } 

    /** 
    * lessThan method 
    * a/b < c/d if c/d > a/b 
    * @param g 
    * @return 
    */ 
    public boolean lessThan(Fraction g) 
    { 
     if (this.greaterThan(g)==false) 
     { 
      return true; 
     } 
     else return false; 
    } 
    @Override 
    public String toString() 
    { 
     return this.getNumerator()+"/"+this.getDenominator(); 
    } 
} 

Это мой тестовый класс, все тесты успешны, за исключением отрицания, я пробовал несколько вариантов, просто умножая на -1 или просто отрицая - без радости.

package Fraction; 
import static org.junit.Assert.*; 

import java.lang.reflect.Method; 

import org.junit.Test; 
import org.junit.Ignore; 
import org.junit.runner.RunWith; 
import org.junit.runners.JUnit4; 

@RunWith(JUnit4.class) 
public class FractionsTest { 

    /** 
    * test methods checking the constructors 
    */ 
    @Test 
    public void testFractionNum_Den() 
    { 
     Fraction f = new Fraction(2,6); 
     assertEquals(1, f.getNumerator()); 
     assertEquals(3, f.getDenominator()); 
    } 
    @Test 
    public void testFractionNum() 
    { 
     Fraction f = new Fraction(5); 
     assertEquals(1, f.getNumerator()); 
     assertEquals(5, f.getDenominator()); 
    } 
    @Test 
    public void testFractionStr() 
    { 
     Fraction f = new Fraction("1/5"); 
     assertEquals(1, f.getNumerator()); 
     assertEquals(5, f.getDenominator()); 

    } 
    @Test 
    public void testNormalize() 
    { 
     Fraction f = new Fraction(2,4); 
     assertEquals(1, f.getNumerator()); 
     assertEquals(2,f.getDenominator()); 
    } 
    /** 
    * Method m=Dummy.class.getDeclaredMethod("foo"); 
    * m.setAccessible(true);//Abracadabra 
     m.invoke(d); 
    */ 
    @Test 
    public void testAdd() 
    { 
     Fraction g = new Fraction(1,3); 
     Fraction toTest = g.add(new Fraction(1,3)); 
     assertEquals(2, toTest.getNumerator()); 
     assertEquals(3, toTest.getDenominator()); 
    } 
    @Test 
    public void testSubtract() 
    { 
     Fraction g = new Fraction (4,6); 
     Fraction toTest = g.substract(new Fraction(2,6)); 
     assertEquals(1, toTest.getNumerator()); 
     assertEquals(3, toTest.getDenominator()); 
    } 
    @Test 
    public void testMultiply() 
    { 
     Fraction g = new Fraction (2,3); 
     Fraction toTest = g.multiply(new Fraction(1,2)); 
     assertEquals(1, toTest.getNumerator()); 
     assertEquals(3, toTest.getDenominator()); 
    } 
    @Test 
    public void testDivide() 
    { 
     Fraction g = new Fraction (2,3); 
     Fraction toTest = g.divide(new Fraction(1,3)); 
     assertEquals(2, toTest.getNumerator()); 
     assertEquals(1, toTest.getDenominator()); 
    } 
    @Test 
    public void testNegate() 
    { 
     Fraction g = new Fraction(1,3); 
     g.negate(); 
     assertEquals(-1, g.getNumerator()); 
     assertEquals(3, g.getDenominator()); 
    } 
    @Test 
    public void testgreaterThan() 
    { 
     Fraction g = new Fraction(1,3); 
     assertEquals(false, g.greaterThan(new Fraction(2,3))); 
     assertEquals(true, g.greaterThan(new Fraction(1,5))); 
    } 
    @Test 
    public void testlessThan() 
    { 
     Fraction g = new Fraction(2,3); 
     assertEquals(false, g.lessThan(new Fraction(1,3))); 
     assertEquals(true, g.lessThan(new Fraction(4,5))); 

    } 

    @Test 
    public void testtoString() 
    { 
     Fraction g = new Fraction(1,3); 
     String f = g.toString(); 
     assertEquals(true, f.contentEquals("1/3")); 
    } 

    } 
+0

эй, FYI Я написал код, на который вы ссылаетесь наверху. :), если это вас интересует, последний и самый лучший сейчас на github: https://github.com/kiprobinson/BigFraction – Kip

ответ

6

Проблема заключается в том, что ваш метод negate возвращает новый Fraction объект, который вы никогда не переназначения в вашей g переменной:

public void testNegate() 
{ 
    Fraction g = new Fraction(1,3); 
    g = g.negate(); //added "g =" 
    assertEquals(-1, g.getNumerator()); 
    assertEquals(3, g.getDenominator()); 
} 

Как примечание стороны, ваш negate метод имеет вопрос, что numerator всегда будет отрицательным из-за умножения абсолютного значения numerator (который всегда будет положительным) на -1. Просто удалите Math#abs использование оттуда:

public Fraction negate() 
{ 
    int num = this.numerator * -1; 
    int den = this.denominator; 
    return new Fraction(num,den); 
} 

пример, чтобы сделать ваш класс неизменны:

public class Fraction { 
    //marking the fields as final in order to only be initialized 
    //in class constructor 
    private final int numerator; 
    private final int denominator; 

    public Fraction() { 
     //always initialize the fields in constructor 
     numerator = 0; 
     denominator = 1; //because it cannot be zero 
    } 

    /** 
    * Constructor with two int parameters 
    * @param num is numerator 
    * @param den is denominator 
    */ 
    public Fraction(int num, int den) { 
     if (den==0) { 
      //denominator cannot be zero 
      //it is better to throw an exception than just returning 
      throw new IllegalArgumentException("Denominator cannot be zero"); 
     } 
     int[] fractionData = this.normalize(num, den); 
     //always initialize the fields in constructor 
     this.numerator = fractionData[0]; 
     this.denominator = fractionData[1]; 
    } 

    private int[] normalize(int numParam, int denParam) { 
     int[] fractionData = new int[2]; 
     fractionData[0] = numParam; 
     fractionData[1] = denParam; 
     BigInteger gcd; 
     BigInteger num = BigInteger.valueOf(numParam); 
     BigInteger den = BigInteger.valueOf(denParam); 
     gcd = num.gcd(den); 
     if (gcd.intValue() > 1) { 
      fractionData[0] = numParam/gcd.intValue(); 
      fractionData[1] = denParam/gcd.intValue(); 
     } 
     return fractionData; 
    } 

    //leaving the rest of the implementation up to you... 
} 
+0

Привет Луиджи. Спасибо за ваши комментарии, но я думаю, что ответ Питера немного опрятен, так как мой тестNegate() по существу провалился, потому что мой Negate() не был разработан достаточно хорошо. Я взял на борт предложение Math # abs. С наилучшими пожеланиями. Грег. – user3274207

+0

@ user3274207, как отмечено почти всеми деталями реализации вашего класса «Фракция», выглядит неизменным, как «String» (за исключением того, что вы забыли отметить поля «числитель» и «знаменатель» как «final»), поэтому, когда реализуя каждую операцию, которую вы заканчиваете, получая полный новый экземпляр «Fraction». В ответе Питера его реализация нарушает неизменность вашего класса, поэтому я просто ограничил свой ответ, чтобы удалить «Math # abs» и вернуть полный новый экземпляр «Fraction». См. Здесь [immutability] (http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) –

+0

@ user3274207 об этом комментарии * создание новых экземпляров всегда дорого *: это верно для объектов, которые может занимать много памяти (RAM), например создавая «Рабочую книгу» из POI Apache, чтобы читать файл Excel размером 10 МБ (или более). Для этого случая * стоимость * создания нового экземпляра объекта «Фракция» может быть проигнорирована, обратите внимание, что ** преждевременная оптимизация - это корень всего зла **: http://programmers.stackexchange.com/q/80084 http : //stackoverflow.com/q/385506/1065197 http://ubiquity.acm.org/article.cfm?id=1513451 –

1

Я бы не создать новый экземпляр фракции, если это не действительно необходимо.

public Fraction negate() 
{ 
    this.numerator *= -1; 
    return this; 
} 

Кроме того, я не думаю, что вам нужно BigInteger в normalize().

Я бы выполнил это как-то так.

private void normalize() 
{ 
    int gcd = gcd(this.numerator, this.denominator); 
    if (gcd > 1) 
    { 
     this.numerator = this.numerator/gcd; 
     this.denominator = this.denominator/gcd; 
    } 
    if (this.denominator < 0){ 
     this.numerator *= -1; 
     this.denominator *= -1; 
    } 
} 
+0

Спасибо, Питер, создание новых экземпляров всегда дорого. – user3274207

Смежные вопросы