自己独立实现的,如果有bug或者错误,欢迎评论区留言!
文档
字段摘要:
修饰符 | 字段 | 解释 |
---|---|---|
static final Fraction | ONE | 分数:1,分子、分母都是1的分数 |
static final Fraction | ZERO | 分数:0,分子是0、分母是1的分数 |
构造方法摘要 :
构造方法 | 解释 |
---|---|
Fraction(String fractionStr) | 根据字符串生成一个分数,支持识别”/"、小数点 |
Fraction(double numerator) | 根据一个double数生成一个分数 |
Fraction(long numerator) | 根据一个整型数字生成一个分数;分子式该数字,分母是1 |
Fraction(long numerator, long denominator) | 根据提供的分子、分母生成分数;numerator:分子,denominator:分母 |
方法摘要 :
修饰符 | 方法 | 解释 |
---|---|---|
int | intValue() | 返回对应分数的int值 |
long | longValue() | 返回对应分数的long 值 |
float | floatValue() | 返回对应分数的float 值 |
double | doubleValue() | 返回对应分数的double 值 |
int | compareTo(Fraction o) | 和另一个分数比大小 |
String | toString() | 以假分数形式返回分数,使用”/“作为分号 |
Fraction | add(Fraction fraction) | 返回两个分数的和,不会改编原分数 |
Fraction | sub(Fraction fraction) | 返回两个分数的差,不会改编原分数 |
Fraction | mul(Fraction fraction) | 返回两个分数的积,不会改编原分数 |
Fraction | div(Fraction fraction) | 返回两个分数的商,不会改编原分数 |
Fraction | clone() | 返回一个克隆对象,深拷贝 |
Fraction | getOppositeNumber(Fraction fraction) | 返回参数的相反数,a的相反数是-a |
Fraction | getReciprocal(Fraction fraction) | 返回参数的倒数,a的倒数是1/a |
boolean | isZero() | 判断该分数是否为0 |
long | getNumerator() | 获取分子 |
long | getDenominator() | 获取分母 |
void | setNumerator(long numerator) | 设置新的分子 |
void | setDenominator(long denominator) | 设置新的分母 |
代码
/**
* @description: 分数
* @author: liangjiayy
* @create: 2022-09-30 23:31
**/
public class Fraction extends Number implements Comparable<Fraction>, Operationable<Fraction> {
/**
* 1
*/
public static final Fraction ONE = new Fraction(1);
/**
* 0
*/
public static final Fraction ZERO = new Fraction(0);
/**
* 分子
*/
private long numerator;
/**
* 分母
*/
private long denominator;
public Fraction(String fractionStr) {
String[] split = fractionStr.trim().split("/");
if (split.length > 2 || split.length == 0) {
throw new RuntimeException("将\"" + fractionStr + "\"转化为分数出现了异常!");
}
Fraction num, den;
//分子
if (split[0].contains(".")) {
num = convertDouble2fraction(Double.parseDouble(split[0]));
} else {
num = new Fraction(Long.parseLong(split[0]));
}
//分母
if (split.length == 2) {
if (split[1].contains(".")) {
den = convertDouble2fraction(Double.parseDouble(split[1]));
} else {
den = new Fraction(Long.parseLong(split[1]));
}
} else {
this.numerator = num.numerator;
this.denominator = num.denominator;
return;
}
Fraction div = num.div(den);
this.numerator = div.numerator;
this.denominator = div.denominator;
}
public Fraction(double numerator) {
Fraction fraction = convertDouble2fraction(numerator);
this.numerator = fraction.numerator;
this.denominator = fraction.denominator;
}
private Fraction convertDouble2fraction(double numerator) {
String[] split = (numerator + "").split("\\.");
//整数部分
long left = Long.parseLong(split[0]);
//小数部分
long right = Long.parseLong(split[1]);
int len = split[1].length();
long pow = (long) Math.pow(10, len);
return new Fraction(left * pow + right, pow);
}
public Fraction(long numerator) {
this(numerator, 1L);
}
public Fraction(long numerator, long denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
/**
* Returns the value of the specified number as an {@code int},
* which may involve rounding or truncation.
*
* @return the numeric value represented by this object after conversion
* to type {@code int}.
*/
@Override
public int intValue() {
return (int) (numerator / denominator);
}
/**
* Returns the value of the specified number as a {@code long},
* which may involve rounding or truncation.
*
* @return the numeric value represented by this object after conversion
* to type {@code long}.
*/
@Override
public long longValue() {
return numerator / denominator;
}
/**
* Returns the value of the specified number as a {@code float},
* which may involve rounding.
*
* @return the numeric value represented by this object after conversion
* to type {@code float}.
*/
@Override
public float floatValue() {
return (float) (1.0 * numerator / denominator);
}
/**
* Returns the value of the specified number as a {@code double},
* which may involve rounding.
*
* @return the numeric value represented by this object after conversion
* to type {@code double}.
*/
@Override
public double doubleValue() {
return 1.0 * numerator / denominator;
}
/**
* Compares this object with the specified object for order. Returns a
* negative integer, zero, or a positive integer as this object is less
* than, equal to, or greater than the specified object.
*
* <p>The implementor must ensure <tt>sgn(x.compareTo(y)) ==
* -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>. (This
* implies that <tt>x.compareTo(y)</tt> must throw an exception iff
* <tt>y.compareTo(x)</tt> throws an exception.)
*
* <p>The implementor must also ensure that the relation is transitive:
* <tt>(x.compareTo(y)>0 && y.compareTo(z)>0)</tt> implies
* <tt>x.compareTo(z)>0</tt>.
*
* <p>Finally, the implementor must ensure that <tt>x.compareTo(y)==0</tt>
* implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
* all <tt>z</tt>.
*
* <p>It is strongly recommended, but <i>not</i> strictly required that
* <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>. Generally speaking, any
* class that implements the <tt>Comparable</tt> interface and violates
* this condition should clearly indicate this fact. The recommended
* language is "Note: this class has a natural ordering that is
* inconsistent with equals."
*
* <p>In the foregoing description, the notation
* <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
* <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
* <tt>0</tt>, or <tt>1</tt> according to whether the value of
* <i>expression</i> is negative, zero or positive.
*
* @param o the object to be compared.
* @return a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the specified object.
* @throws NullPointerException if the specified object is null
* @throws ClassCastException if the specified object's type prevents it
* from being compared to this object.
*/
@Override
public int compareTo(Fraction o) {
Fraction[] fractions = convert2sameDenominator(this, o);
//如果分母是正数,比较分子
if (fractions[0].denominator > 0) {
return Long.compare(fractions[0].numerator, fractions[1].numerator);
}
return -Long.compare(fractions[0].numerator, fractions[1].numerator);
}
/**
* 通分,将两个分数转化成同分母分数
*
* @param f1
* @param f2
* @return Fraction[0]:第一个分数转化后的结果,Fraction[1]:第二个分母转化后的结果
*/
private Fraction[] convert2sameDenominator(Fraction f1, Fraction f2) {
//找公倍数
long leastCommonMultiple = findLeastCommonMultiple(f1.denominator, f2.denominator);
Fraction[] res = new Fraction[2];
//转化为指定的分母
res[0] = convertDenominator(f1, leastCommonMultiple);
res[1] = convertDenominator(f2, leastCommonMultiple);
return res;
}
/**
* 将分数的分母转化为指定的值
* 注意:新的分母必须是旧的分母的倍数
*
* @param fraction
* @param denominator 新的分母
* @return
*/
private Fraction convertDenominator(Fraction fraction, long denominator) {
if (denominator % fraction.denominator != 0) {
throw new RuntimeException("无法将\"" + fraction + "\"转化为分母为" + denominator + "的分数!");
}
return new Fraction(fraction.numerator * (denominator / fraction.denominator), denominator);
}
/**
* 找最小公倍数
*
* @param num1
* @param num2
* @return
*/
private long findLeastCommonMultiple(long num1, long num2) {
//找公因数
long greatestCommonDivisor = findGreatestCommonDivisor(num1, num2);
//公倍数
return num1 * num2 / greatestCommonDivisor;
}
/**
* 找最大公因数
*
* @param num1
* @param num2
* @return
*/
private long findGreatestCommonDivisor(long num1, long num2) {
//辗转相除法
long tmp;
while (num2 != 0) {
tmp = num1 % num2;
num1 = num2;
num2 = tmp;
}
return num1;
}
@Override
public String toString() {
Fraction fraction = convert2theSimplestFraction(this);
this.numerator = fraction.numerator;
this.denominator = fraction.denominator;
//分母等于1,只返回分子
if (denominator == 1) {
return numerator + "";
}
if (numerator == 0) {
return 0 + "";
}
return numerator + "/" + denominator;
}
/**
* 加法
*
* @param fraction
* @return
*/
@Override
public Fraction add(Fraction fraction) {
//通分
Fraction[] fractions = convert2sameDenominator(this, fraction);
//分子相加
Fraction res = new Fraction(fractions[0].numerator + fractions[1].numerator, fractions[0].denominator);
//化简为最简带分数
return convert2theSimplestFraction(res);
}
/**
* Creates and returns a copy of this object. The precise meaning
* of "copy" may depend on the class of the object. The general
* intent is that, for any object {@code x}, the expression:
* <blockquote>
* <pre>
* x.clone() != x</pre></blockquote>
* will be true, and that the expression:
* <blockquote>
* <pre>
* x.clone().getClass() == x.getClass()</pre></blockquote>
* will be {@code true}, but these are not absolute requirements.
* While it is typically the case that:
* <blockquote>
* <pre>
* x.clone().equals(x)</pre></blockquote>
* will be {@code true}, this is not an absolute requirement.
* <p>
* By convention, the returned object should be obtained by calling
* {@code super.clone}. If a class and all of its superclasses (except
* {@code Object}) obey this convention, it will be the case that
* {@code x.clone().getClass() == x.getClass()}.
* <p>
* By convention, the object returned by this method should be independent
* of this object (which is being cloned). To achieve this independence,
* it may be necessary to modify one or more fields of the object returned
* by {@code super.clone} before returning it. Typically, this means
* copying any mutable objects that comprise the internal "deep structure"
* of the object being cloned and replacing the references to these
* objects with references to the copies. If a class contains only
* primitive fields or references to immutable objects, then it is usually
* the case that no fields in the object returned by {@code super.clone}
* need to be modified.
* <p>
* The method {@code clone} for class {@code Object} performs a
* specific cloning operation. First, if the class of this object does
* not implement the interface {@code Cloneable}, then a
* {@code CloneNotSupportedException} is thrown. Note that all arrays
* are considered to implement the interface {@code Cloneable} and that
* the return type of the {@code clone} method of an array type {@code T[]}
* is {@code T[]} where T is any reference or primitive type.
* Otherwise, this method creates a new instance of the class of this
* object and initializes all its fields with exactly the contents of
* the corresponding fields of this object, as if by assignment; the
* contents of the fields are not themselves cloned. Thus, this method
* performs a "shallow copy" of this object, not a "deep copy" operation.
* <p>
* The class {@code Object} does not itself implement the interface
* {@code Cloneable}, so calling the {@code clone} method on an object
* whose class is {@code Object} will result in throwing an
* exception at run time.
*
* @return a clone of this instance.
* @throws CloneNotSupportedException if the object's class does not
* support the {@code Cloneable} interface. Subclasses
* that override the {@code clone} method can also
* throw this exception to indicate that an instance cannot
* be cloned.
* @see Cloneable
*/
@Override
protected Fraction clone() {
return new Fraction(this.numerator, this.denominator);
}
/**
* 约分
*
* @param fraction
* @return
*/
private Fraction convert2theSimplestFraction(Fraction fraction) {
long leastCommonMultiple = findGreatestCommonDivisor(fraction.numerator, fraction.denominator);
if (leastCommonMultiple == 1) {
return fraction.clone();
}
//分子分母,同时除以最大公约数
return new Fraction(fraction.numerator / leastCommonMultiple, fraction.denominator / leastCommonMultiple);
}
/**
* 减法
*
* @param fraction
* @return
*/
@Override
public Fraction sub(Fraction fraction) {
// 相反数
fraction = getOppositeNumber(fraction);
return add(fraction);
}
/**
* 相反数
*
* @param fraction
* @return
*/
@Override
public Fraction getOppositeNumber(Fraction fraction) {
return new Fraction(-fraction.numerator, fraction.denominator);
}
/**
* 乘法
*
* @param fraction
* @return
*/
@Override
public Fraction mul(Fraction fraction) {
Fraction res = new Fraction(numerator * fraction.numerator, denominator * fraction.denominator);
return convert2theSimplestFraction(res);
}
/**
* 除法
*
* @param fraction
* @return
*/
@Override
public Fraction div(Fraction fraction) {
fraction = getReciprocal(fraction);
return mul(fraction);
}
/**
* 倒数
*
* @param fraction
* @return
*/
@Override
public Fraction getReciprocal(Fraction fraction) {
return new Fraction(fraction.denominator, fraction.numerator);
}
public boolean isZero() {
return this.numerator == 0;
}
/**
* 分子
*
* @return
*/
public long getNumerator() {
return numerator;
}
/**
* 分母
*
* @return
*/
public long getDenominator() {
return denominator;
}
public void setNumerator(long numerator) {
this.numerator = numerator;
}
public void setDenominator(long denominator) {
this.denominator = denominator;
}
}
/**
* 支持运算的,包括加、减、乘、除
*/
interface Operationable<T> {
/**
* 加法
*
* @param t
* @return
*/
T add(T t);
/**
* 减法
*
* @param t
* @return
*/
T sub(T t);
/**
* 乘法
*
* @param t
* @return
*/
T mul(T t);
/**
* 除法
*
* @param t
* @return
*/
T div(T t);
/**
* 相反数
*
* @param fraction
* @return
*/
Fraction getOppositeNumber(Fraction fraction);
/**
* 倒数
*
* @param fraction
* @return
*/
Fraction getReciprocal(Fraction fraction);
}