Java 分数计数器 类

Java fraction counter with classes

由于某种原因,我在作业上遇到了困难。我有一个程序从输入文件中读取分数,将每一行分配给一个字符串,然后将内容保存到 class 分数(分子和分母)。然后将分数对象保存到名为 fractionList.

的数组中

我有另一个 class FractionCounter 计算简化形式的分数的出现次数,如果有任何重复,那么程序将简单地添加到整数 "counter"那个对象。 FractionCounter 个对象存储在一个名为 fracCount.

的对象列表中

我的问题是当我将一个对象添加到 FractionCounter 个对象的 fracCount 列表时。我正在使用一个分支语句来确定我是否应该添加一个新的分数元素(一个不匹配数组 fracCount 中其他分数的任何简化形式的元素)到 fracCount,或者如果我应该在共享相同减少分数值的元素中向 counter 变量添加一个值。

一切正常,除非我试图确定派系对象是否为副本。使用我的代码,我的 fracCount 数组是空的。

这是我的代码

public class Fraction {
    private int numerator;
    private int denominator;

    Fraction(){ // default, no arg constructor
    }
    // constructor that initializes data
    Fraction(int numerator, int denominator){
        this.numerator = numerator;
        if(denominator > 1000){
            this.denominator = 1;
        }else if(numerator == denominator){
            this.numerator = 1;
            this.denominator = 1;
        }else if(denominator == 0){
            System.out.println("Zero is not a valid denominator");
        }else{
            this.denominator = denominator;
        }
    }
    // compares this fraction object to 'other' fraction object
    boolean equals(Fraction other){
        if(this.numerator == other.numerator && 
                this.denominator == other.denominator){
            return true;
        }else if((this.numerator / this.denominator) ==
                (other.numerator / other.denominator)){
            return true;
        }else{
            return false;
        }
    }
    // gives user access to the numerator and denominator
    public int getNumerator(){
        return this.numerator;
    }
    public int getDenominator(){
        return this.denominator;
    }   
}

public class FractionCounter extends Fraction{
    private Fraction theFraction;
    private int counter = 1;

    FractionCounter(Fraction theFraction){
        this.theFraction = theFraction;
    }
    public boolean compareAndIncrement(Fraction newFraction){
        if((theFraction.getNumerator() / theFraction.getDenominator() == 
                newFraction.getNumerator() / newFraction.getDenominator())){
            this.counter++;
            return true;
        }else if(theFraction.getDenominator() == 0 || 
                newFraction.getDenominator() == 0){
            return false;
        }else{
            return false;
        }
    }
}

public class ObjectList {
    private int N;
    private Fraction[] fractionList;
    private int numElements = 0;

    public ObjectList(int n){
        this.N = n;
        this.fractionList = new Fraction[N];
    }
    public void add(Fraction next){
        fractionList[numElements] = next;
        numElements++;
    }
    public int size(){
        return this.numElements;
    }
    public Fraction getFraction(int i){
        return fractionList[i];
    }
}

    import java.util.Scanner;
    import java.awt.List;
    import java.io.*;
    import java.util.Arrays;

    public class FractionDriver {
    public static void main(String[] args){

        // creates scanner object
        Scanner fractions = null;

        // uses scanner to import fractions file and read how many lines 
        try{
            fractions = new Scanner(new FileInputStream("fractions.txt"));
        }catch(FileNotFoundException e){
            System.out.println("Cannot find fractions.txt");
            System.exit(0);
        }

        // creates a large array that stores the text file
        String[] input = new String[100];

        int numLines = 0; // counts the number of fractions
        int numElement = 0; // counts the current index element
        while(fractions.hasNextLine()){
            input[numElement] = fractions.next();
            numElement++;
            numLines++;
        }
        fractions.close(); // closes the input stream

        // create object list of fractions
        ObjectList fractionList = new ObjectList(numLines);
        ObjectList fractCount = new ObjectList(numLines);

        int totalFractions = 0;

        for(int i = 0; i < numLines; i++){

            totalFractions++; // adds one on every new line

            // creates an array for each fraction where frac[0] is the 
            // numerator and frac[1] is the denominator
            String[] fract = input[i].split("/"); 

            // converts the string values to integers
            int numerator = Integer.parseInt(fract[0]);
            int denom = Integer.parseInt(fract[1]);

            // creates a fraction object and assigns instance variables
            Fraction f = new Fraction(numerator, denom);
            FractionCounter count = new FractionCounter(f);

            // adds the fraction to the array if the denominator
            // is not zero
            if(f.getDenominator() != 0){
                fractionList.add(f);
                for(int j = 0; j < totalFractions; j++){
                    if(fractCount.getFraction(j) != null){
                        if(!f.equals(fractCount.getFraction(j))){
                            fractCount.add(count);
                        }else{
                            count.compareAndIncrement(f);
                        }
                    }
                }
            }   
        }
    }
}

问题是你在除整数吗?

  numerator/denominator

4/61/7 相除会发生什么?对于整数,它们都将产生 0,因此您会得到意想不到的相等性。

您可以转换为双倍

  (double)numerator/(double)demoninator

但记住浮点比较是否相等并不明显,通常我们测试

 if ( ( oneDouble - anotherDouble ) < someTinyValue )

我认为这是给您带来问题的行(在 Fraction.equals 方法中:

 (this.numerator / this.denominator) == (other.numerator / other.denominator)

它当前正在执行整数除法,因此 1/2 == 0 和 1/3 == 0,因此您的代码认为每个分数都已经在分数列表中。

您需要使用某种 epsilon 执行浮点运算。

Why Are Floating Point Numbers Inaccurate?

有一种非常自然的方法可以检查两个简单分数的值是否相等,而无需将它们转换为浮点数。

如果a/b = c/d,则ad = bcbd=0除外),所以:

boolean equals(Fraction other) {
    if (this.denominator == 0 || other.denominator == 0)
         return false; // undefined
    return this.numerator * other.denominator == other.numerator * this.denominator;
}