Java实现分数

自己独立实现的,如果有bug或者错误,欢迎评论区留言!

文章目录

文档

字段摘要:

修饰符字段解释
static final FractionONE分数:1,分子、分母都是1的分数
static final FractionZERO分数:0,分子是0、分母是1的分数

构造方法摘要 :

构造方法解释
Fraction(String fractionStr)根据字符串生成一个分数,支持识别”/"、小数点
Fraction(double numerator)根据一个double数生成一个分数
Fraction(long numerator)根据一个整型数字生成一个分数;分子式该数字,分母是1
Fraction(long numerator, long denominator)根据提供的分子、分母生成分数;numerator:分子,denominator:分母

方法摘要 :

修饰符方法解释
intintValue()返回对应分数的int值
longlongValue()返回对应分数的long 值
floatfloatValue()返回对应分数的float 值
doubledoubleValue()返回对应分数的double 值
intcompareTo(Fraction o)和另一个分数比大小
StringtoString()以假分数形式返回分数,使用”/“作为分号
Fractionadd(Fraction fraction)返回两个分数的和,不会改编原分数
Fractionsub(Fraction fraction)返回两个分数的差,不会改编原分数
Fractionmul(Fraction fraction)返回两个分数的积,不会改编原分数
Fractiondiv(Fraction fraction)返回两个分数的商,不会改编原分数
Fractionclone()返回一个克隆对象,深拷贝
FractiongetOppositeNumber(Fraction fraction)返回参数的相反数,a的相反数是-a
FractiongetReciprocal(Fraction fraction)返回参数的倒数,a的倒数是1/a
booleanisZero()判断该分数是否为0
longgetNumerator()获取分子
longgetDenominator()获取分母
voidsetNumerator(long numerator)设置新的分子
voidsetDenominator(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)&gt;0 &amp;&amp; y.compareTo(z)&gt;0)</tt> implies
     * <tt>x.compareTo(z)&gt;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);
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值