【问题标题】:Reading in monetary amounts by text file & calculating bill denominations通过文本文件读取货币金额并计算票据面额
【发布时间】:2019-09-09 02:23:31
【问题描述】:

我应该将一个文本文件读入 java 程序,在 java 文件中添加货币金额,然后确定如何支付每个总金额(读取 $20、$10、$5...)。我在如何处理分隔文本文件的每一行以进行单独计算时遇到了麻烦。

这是我要导入的文本文件:

Class1  9.30    7.44    5.32    3.33
Class2  2.22
Class3  7.33    4.44    3.56
Class4  15.67   12.02   10.33   8.87
Class5  4.44    3.33    2.22    1.11

我不仅应该为每个值展示解决方案,还应该为每个类展示解决方案。我假设需要某种 for 循环,但我无法弄清楚。

public static void main(String[] args) throws FileNotFoundException, IOException {

    FileReader file = new FileReader("C:\\Users\\idhit\\Desktop\\amounts.txt");
    BufferedReader bf = new BufferedReader(file);

    String st = bf.readLine();

    double sum = 0;
    double c1total = 0;
    double c2total = 0;
    double c3total = 0;
    double c4total = 0;
    double c5total = 0;

    while ((st = bf.readLine()) != null) {

        StringTokenizer stn = new StringTokenizer(st);
        String rn = stn.nextToken();
        String name = stn.nextToken();
        double c1 = Double.parseDouble(stn.nextToken());
        double c2 = Double.parseDouble(stn.nextToken());
        double c3 = Double.parseDouble(stn.nextToken());
        double c4 = Double.parseDouble(stn.nextToken());
        double c5 = Double.parseDouble(stn.nextToken());

    }

    double value = scan.nextDouble();
    int valueIntegral = (int) value;
    int valueFractional = (int) Math.round(100 * value - 100 * valueIntegral);

    // Integral values

    int hundred = valueIntegral / 100;

    int fifty = (valueIntegral % 100) / 50;

    int twenty = ((valueIntegral % 100) % 50) / 20;

    int ten = (((valueIntegral % 100) % 50) % 20) / 10;

    int five = ((((valueIntegral % 100) % 50) % 20) % 10) / 5;

    int one = (((((valueIntegral % 100) % 50) % 20) % 10) % 5) / 1;

    // Fractional values

    int quarter = valueFractional / 25;

    int dime = (valueFractional % 25) / 10;

    int nickel = ((valueFractional % 25) % 10) / 5;

    int penny = (((valueFractional % 25) % 10) % 5) / 1;

    System.out.println(hundred + " hundred dollar bills\n" + fifty + " fifty dollar bills\n" + twenty
            + " twenty dollar bills\n" + ten + " ten dollar bills\n" + five + " five dollar bills\n" + one
            + " one dollar bills\n" + quarter + " quarters\n" + dime + " dimes\n" + nickel + " nickels\n" + penny
            + " pennies");
}

【问题讨论】:

  • 我回答你的问题了吗?
  • 请注意,您对valueFractional 的计算可能会出现浮点错误,并且有时会给出一个太小的结果。
  • 请检查更新答案。
  • 是的,我认为这可行。只是遇到了“非法的表达开始”。感谢您的帮助!

标签: java bufferedreader filereader


【解决方案1】:

您的方向是正确的,但是根据名称为每个班级分配总数,您需要一些条件。假设您的 bufferedReader 读取第 1 行,即

Class1  9.30    7.44    5.32    3.33

您可以从 StringTokenizer 获取每个班级的姓名和总金额。 每次调用 .nextToken() 时,它都会读取到下一个分隔符。在您的情况下,它是空格。第一个.nextToken() 将读取Class1。第二个将读取9.30 等等...

Class 1: 25.39

如果名字是Class1,你可以从这里开始输入c1total。敲响任何铃铛?是的,你猜对了。您将在此处使用 if 语句。因为你有 5 个类,所以你有 5 个 if 语句。您的每个 while 将处理每一行并使用 if 语句将其分配给正确的变量。

我建议您尝试我上面写的内容,但是我以不同的方式做同样的事情只是为了给您一个洞察力,以及如何以不同的方式对同一事物进行编程,甚至可能更好。

编辑:就像 DawoodibnKareem 建议的那样。 StringTokenizer 是旧版,不应使用。我已经更新了代码。它现在使用 split 和 BigDecimal 而不是 double。

// Instead of 5 variables I created an array to store data
BigDecimal[] classTotal = new BigDecimal[5];
String line;
while ((line = bufferedReader.readLine()) != null) {
    String[] lineSplit = line.split("\\s+");
    // Class1 9.30 7.44 5.32 3.33 would become
    // [Class1, 9.30, 7.44, 5.32, 3.33]
    String name = lineSplit[0];
    switch (name) {
    case "Class1":
        classTotal[0] = getSum(lineSplit);
        break;
    case "Class2":
        classTotal[1] = getSum(lineSplit);
        break;
    case "Class3":
        classTotal[2] = getSum(lineSplit);
        break;
    case "Class4":
        classTotal[3] = getSum(lineSplit);
        break;
    case "Class5":
        classTotal[4] = getSum(lineSplit);
        break;

    }
}
bufferedReader.close();
for (int i = 0; i < classTotal.length; i++) {
    System.out.println("Class " + (i + 1) + " : " + classTotal[i]);
}

public static BigDecimal getSum(String[] line) {
    BigDecimal sum = new BigDecimal(0);
    // Iterating from index 1 because 0 index contains name
    for (int i = 1; i < line.length; i++) {
        BigDecimal valueBigDecimal = new BigDecimal(line[i]);
        sum = sum.add(valueBigDecimal);
    }
    return sum;
}

输出:

Class 1 : 25.39
Class 2 : 2.22
Class 3 : 15.33
Class 4 : 46.89
Class 5 : 11.10

输出:(如果我使用 double 而不是 BigDecimal)

Class 1 : 25.39
Class 2 : 2.22
Class 3 : 15.33
Class 4 : 46.88999999999999
Class 5 : 11.1

请注意某些值是如何关闭的,尤其是对于 Class 4 应该是 46.89

这是因为 Java 中的 float 和 double 基本类型是 floating point 数字,其中数字存储为分数和指数的二进制表示。浮点数有时(可以安全地假设“大部分时间”)无法返回数字的精确表示。因此你得到46.88999999999999 而不是46.89。这就是为什么 double/float 在计算货币时被认为是可怕的。为了避免这个问题,我们必须使用BigDecimal。特别是在您对 double 进行进一步计算只会降低精度的情况下。

【讨论】:

  • 请注意 Javadoc 对 StringTokenizer 类的描述 - "... StringTokenizer 是一个遗留类,出于兼容性原因保留,但不鼓励在新代码中使用它。建议任何寻求此功能的人都使用 String 的 split 方法或 java.util.regex 包来代替......"。在这种情况下,使用Scanner(OP 最初使用它的方式)是一个更好的选择。此外,此解决方案中的加法会产生浮点舍入误差,并且会经常给出错误的结果。
  • @DawoodibnKareem 你是对的。我将更新我的代码以使用更好的类,并将添加有关 floating point rounding errors 的信息。
  • 我了解您对@Goion 的看法。我仍在处理输出,但感谢您的帮助!
  • 是的,好多了。
猜你喜欢
  • 2015-08-28
  • 2019-11-04
  • 1970-01-01
  • 2013-03-27
  • 2020-12-20
  • 1970-01-01
  • 1970-01-01
  • 2011-11-26
相关资源
最近更新 更多