You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Java话费计算程序返回6.999999999999993而非预期值7?

问题原因:浮点数的二进制精度缺陷

这是因为double(以及所有二进制浮点数)无法精确表示0.1这个十进制小数——就像十进制里没法精确写出1/3(0.333...)一样,0.1转成二进制是无限循环的小数,double只能存储它的近似值。你每次循环累加这个近似值,误差会不断累积,20次累加后就出现了明显的偏差,导致结果变成6.999999999999993而不是预期的7。

而0.5是2的负一次方(1/2),能被二进制精确表示,所以累加的时候不会有误差,结果自然正确。


解决方案

推荐下面几种彻底解决的办法:

1. 用整数处理金额(最稳妥)

把所有金额单位换成美分,用int或long计算,最后再转成美元。完全规避浮点数误差:

import java.util.*;
public class MobilePhoneCharges 
{
    public static void main(String[] args) 
    {
        int cents = 0; // 用美分做单位
        String userInput;
        Scanner sc = new Scanner(System.in);
        System.out.print("Hello! Welcome to MOBILEPHONECOMPANY! \nPlease enter the type of customer you are! ");
        userInput = sc.nextLine();

        if(userInput.equals("r") || userInput.equals("c") || userInput.equals("p") ) {
            System.out.println("Please enter in how many minutes you have used! ");
            int minutes = sc.nextInt();

            if (userInput.equals("r") && minutes>0) {
                cents += 500; // 5美元 = 500美分
                if(minutes > 60) {
                    int extraMinutes = minutes - 60;
                    cents += extraMinutes * 10; // 每分钟10美分
                }
                // 转成美元输出
                System.out.printf("You owe %.2f!\n", cents / 100.0);
            }
        }
        sc.close();
    }
}

2. 使用BigDecimal精确计算

如果必须用小数,用BigDecimal代替double,指定精确的舍入规则:

import java.math.BigDecimal;
import java.util.*;
public class MobilePhoneCharges 
{
    public static void main(String[] args) 
    {
        BigDecimal money = BigDecimal.ZERO;
        String userInput;
        Scanner sc = new Scanner(System.in);
        System.out.print("Hello! Welcome to MOBILEPHONECOMPANY! \nPlease enter the type of customer you are! ");
        userInput = sc.nextLine();

        if(userInput.equals("r") || userInput.equals("c") || userInput.equals("p") ) {
            System.out.println("Please enter in how many minutes you have used! ");
            int minutes = sc.nextInt();

            if (userInput.equals("r") && minutes>0) {
                money = money.add(new BigDecimal("5.00"));
                if(minutes > 60) {
                    int extraMinutes = minutes - 60;
                    // 用字符串构造BigDecimal,避免浮点数传入的误差
                    money = money.add(new BigDecimal("0.10").multiply(new BigDecimal(extraMinutes)));
                }
                System.out.println("You owe "+money+"!");
            }
        }
        sc.close();
    }
}

3. 优化计算逻辑(临时缓解)

不要用循环累加0.1,直接计算超出分钟数乘以0.1,减少误差次数(虽然还是可能有微小误差,但大部分场景下显示时可以通过格式化消除):

import java.util.*;
public class MobilePhoneCharges 
{
    public static void main(String[] args) 
    {
        double money = 0;
        String userInput;
        Scanner sc = new Scanner(System.in);
        System.out.print("Hello! Welcome to MOBILEPHONECOMPANY! \nPlease enter the type of customer you are! ");
        userInput = sc.nextLine();

        if(userInput.equals("r") || userInput.equals("c") || userInput.equals("p") ) {
            System.out.println("Please enter in how many minutes you have used! ");
            int minutes = sc.nextInt();

            if (userInput.equals("r") && minutes>0) {
                money += 5;
                if(minutes > 60) {
                    int extraMinutes = minutes - 60;
                    money += extraMinutes * 0.10; // 直接计算,不用循环
                }
                // 格式化输出保留两位小数
                System.out.printf("You owe %.2f!\n", money);
            }
        }
        sc.close();
    }
}

内容的提问来源于stack exchange,提问作者Mont Blac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 14:55:14