我如何否定Java分数,一个我';我创造了
这是我的分数类代码,有几种方法,我的要求是将分子作为分母保留为我如何否定Java分数,一个我';我创造了,java,Java,这是我的分数类代码,有几种方法,我的要求是将分子作为分母保留为int: /** * @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/git
int
:
/**
* @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();
}
}
问题在于
negate
方法返回一个新的分数
对象,而您从未将该对象重新分配给g
变量:
public void testNegate()
{
Fraction g = new Fraction(1,3);
g = g.negate(); //added "g ="
assertEquals(-1, g.getNumerator());
assertEquals(3, g.getDenominator());
}
作为旁注,您的
否定
方法存在一个问题,即分子
将始终为负,因为将分子
的绝对值(始终为正)乘以-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...
}
除非真的需要,否则我不会创建分数的新实例
public Fraction negate()
{
this.numerator *= -1;
return this;
}
另外,我认为在normalize()
中不需要BigInteger
我会像这样实现它
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;
}
}
private void normalize()
{
int gcd=gcd(这个分子,这个分母);
如果(gcd>1)
{
this.numerator=this.numerator/gcd;
this.densor=this.densor/gcd;
}
if(该分母<0){
这个。分子*=-1;
这个分母*=-1;
}
}
Hi Luiggi。谢谢你的评论,但我认为Peter的回答稍微简洁了一点,因为我的testNegate()基本上失败了,因为我的Negate()设计得不够好。我接受了数学abs的建议。顺致敬意,Greg.@user3274207正如您的分数
类的几乎所有实现细节所指出的,它看起来像字符串
一样是不可变的(除了您忘记将分子
和分母
字段标记为最终
),因此,在实现每个操作时,您都会通过检索Fraction
的一个全新实例来结束。在Peter的回答中,他的实现打破了类的不变性,这就是为什么我只是将我的回答限制为删除Math#abs
,并返回一个全新的分数
实例。有关此注释,请参见此处@user3274207。创建新实例的成本总是很高的:对于可能占用大量内存(RAM)的对象来说,这是正确的,例如,从Apache POI创建工作簿来读取10MB(或更多)Excel文件。在这种情况下,创建一个新的Fraction
对象实例的成本可以忽略,请注意,过早优化是万恶之源:嗨,Luiggi,谢谢你的评论。事实上,正如你提到的,彼得的答案打破了不变性,我的分数应该是不变性的。所以我现在就用你的答案!与成本相同,创建一个int对象实际上并不需要那么多内存。非常感谢您关注这件事并向我解释。我对将分子和分母字段初始化为final有一个问题。当我这样做时,Eclipse会抱怨每种方法:“空白的最终字段分子可能尚未初始化”或“最终字段分数。分子(或分母)无法分配,建议将其更改回。谢谢Peter,创建新实例的成本总是很高。嘿,仅供参考,我在顶部编写了您引用的代码。:)如果您对它感兴趣,最新和最好的版本现在位于github上:
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;
}
}