为什么我的代码比数学多输出一个?

Why is my code outputting one more than the math?

好的,所以我正在编写一个贷款计算器,其中在六个月的时间内从之前的金额中减去剩余贷款金额的 10%。问题不难,就是我写的代码好像……呃……智障。

import java.util.Scanner;

public class Program
{
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int amount = scanner.nextInt();
        
        int payment;

        for (int month = 0; month < 6; month++)
        {
            payment = amount / 10;
            
            amount -= payment;
        }

        System.out.println(amount);
        
    }
}

代码可以正常工作,但我计算了一下,amount 的输出正好比应有的多 1。是否有某种 Java 规则我还没有学会或什么?

当您处理整数时,可能会发生这种情况,因为“.”之后的部分。丢失了。让我们举例说明您的问题: 假设您的金额为 100,因此付款为:

100 / 10 = 10

90 / 10 = 9

81 / 10 = 8

73 / 10 = 7

66 / 10 = 6

60 / 10 = 6 -(这是您期望数字为 5 的地方,但这不是因为您在之前的所有计算中都丢失了小数部分)

输出:54

我个人认为对于这样的计算你应该使用双精度而不是整数

解决方案

以下代码将为您提供四舍五入到小数点后两位的结果。

正如评论中已经提到的那样,当您对整数执行 76 / 10 时,结果将为 7,因此小数部分将丢失。

所以在下面的解决方案中,我使用双精度而不是整数,并且按照您对货币的期望,将结果四舍五入到小数点后两位。

import java.util.Scanner;

public class Programm
{
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double amount = scanner.nextDouble();
        
        double payment;
        try {
        for (int month = 0; month < 6; month++)
        {
            
            payment = amount / 10;
            
            amount -= payment;
            amount = Math.round(100.0 * amount) / 100.0;
            }
        }catch(Exception e) {
            System.out.println("Zero Divivided");
        }

        System.out.println(amount);
        
    }
}

对于输入 100,代码生成结果 53.15

使用 Double 而不是 int,并且始终使用 2 个小数点,因为这是货币

public class Program {
  public static void main(String[] args) {
     Scanner scanner = new Scanner(System.in);
     double  amount = scanner.nextDouble();
     double payment;

     for (int month = 0; month < 6; month++) {
            payment = amount / 10;
            BigDecimal bd = new BigDecimal(payment).setScale(2, RoundingMode.HALF_UP);
            amount -= bd.doubleValue();
     }

     System.out.println(amount);
}

}

好问题的特点之一是包含您的输入和输出。在您的情况下,每行输入都会产生一行输出。你应该在你的问题中输入一个 3 列 table。第一列应该是输入整数,第二列应该是预期的输出值(您的定义),第三列应该是代码为该输入生成的值。一旦达到可以生成此 table 的程度,就可以构建测试了。

就您的代码而言,您可以使用类似的东西对其进行测试,而无需学习任何有关 JUnit 的知识。下面的脚本非常简单,并且使用了您无论如何都应该学习的工具。嗯,也就是说,如果您打算在余下的职业生涯中使用真正的操作系统。您可以使用这些工具来测试许多代码,而不管其语言如何。

这是针对您的特定程序的测试 shell 脚本:

javac Program.java
if [ $? -ne 0 ]; then
   exit 1;
fi

while read line; do
    echo $line > tmp
    java Program < tmp
done < test.dat > test.out

diff test.out test.spec

这是执行它的一种方法:

$ sh test.sh

这是您的代码由 运行 脚本生成的内容:

$ cat test.out
54
533
5315
53145
268
2658
26573
265721

如果所有测试都通过,则脚本不会产生任何输出。这是该脚本使用的测试数据。

$ cat test.dat
100
1000
10000
100000
500
5000
50000
500000

这里是这些数据输出的规范,因为您说您的代码产生的输出正好比您预期的多一个。

cat test.spec
53
532
5314
53144
267
2657
26572
265720

这是脚本生成的内容,因为代码不满足您的规范:

$ sh test.sh
1,8c1,8
< 54
< 533
< 5315
< 53145
< 268
< 2658
< 26573
< 265721
---
> 53
> 532
> 5314
> 53144
> 267
> 2657
> 26572
> 265720

如果您在程序的两个地方将 int 更改为 double,那么脚本将生成以下内容:

$ sh test.sh
1,8c1,8
< 53.1441
< 531.441
< 5314.41
< 53144.1
< 265.7205
< 2657.205
< 26572.05
< 265720.5
---
> 53
> 532
> 5314
> 53144
> 267
> 2657
> 26572
> 265720

如果你想 floor 输出值,那么你可以使用 String.format,也许它会符合规范。在这种情况下不会,因为我盲目地遵循您的定义(比预期多 1 个)。但是,如果您接受测试驱动开发,您将会走得更远。