我的代码无法正常工作。十进制输出不是应该的

时间:2018-09-11 12:19:17

标签: java

我的代码如下:

import java.util.Scanner;

public class MoVerkoopPrijs {

public static void main(String[] args) {
    float inkoopPrijs;
    final int BTW_HOOG = 21;
    final int BTW_LAAG = 6;
    double winstMarge;

    Scanner in = new Scanner(System.in);

    //hieronder wordt je inkoopprijs gevraagd en die moet je dan invoeren
    System.out.println("wat is jouw inkoopprijs?");
    inkoopPrijs = in.nextFloat();

    //hieronder wordt je winstmarge gevraagd en die moet je dan ook invoeren
    System.out.println("wat is jouw winstmarge?");
    winstMarge = in.nextDouble();

    //hieronder zie je de formules hoe je exlusief of inclusief BTW berekend
    //hieronder zie je ook wat je moet doen als je de verkoopprijs wilt berekenen.
    double winstGetal = (winstMarge / 100);
    double verkoopPrijs = inkoopPrijs * (1 + winstGetal);
    double inclusiefBtwLaag = (verkoopPrijs / 100) * BTW_LAAG + verkoopPrijs;
    double inclusiefBtwHoog = (verkoopPrijs / 100) * BTW_HOOG + verkoopPrijs;

    //hieronder print je dan de uiteindelijke prijzen uit
    System.out.println("Verkoopprijs exclusief BTW:" + verkoopPrijs );
    System.out.println("Verkoopprijs inclusief 6% BTW:" + inclusiefBtwLaag );
    System.out.println("Verkoopprijs inclusief 21% BTW:" + inclusiefBtwHoog );

}

}

当前输出为:

Verkoopprijs exclusief BTW: 17.726400604248045

Verkoopprijs inclusief 6% BTW: 18.78998464050293

Verkoopprijs inclusief 21% BTW: 21.448944731140134

但是代码将输出中的最后两位小数弄乱了。 6%的实际输出应为:18.789984000000004。我的代码有什么问题?

我尝试过从float转换为int并翻倍,但没有一个对我有用。

1 个答案:

答案 0 :(得分:2)

计算机不是魔术。它们不能以无限的精度表示数字,因为这将需要不存在的无限内存。他们使用一种创新的解决方案来尝试以某种方式表示浮点数,从而涵盖您想表示的大多数数字,而这些数字仍然可以容纳32位(浮点数)或64位(双精度数)。但这确实是 inexact 。实际上,double / float只能表示有限数量的特定数字,如果您尝试使一个数字不是其中之一,那么您会得到它可以代表的最接近的数字。

那么,哪些数字可以和不能表示? 非常棘手,因为计算机以2为基数工作,而人类则倾向于以10为基数。

这带来了两个重要的教训:

  1. 每当您“渲染”双精度或浮点数(即向用户显示或将其显示为字符串)时,您必须指定给计算机正在寻找。 “仅打印”将不起作用,并且,如果尝试这样做(例如,使用System.out.println(someDouble);,计算机只会猜测并且通常会猜错。这是正确的做法:System.out.printf("%.2f\n", someDouble),或者如果您不这样做, t要打印但要转换为字符串,String.format("%.2f", someDouble):您要告诉java打印/字符串化它,以便在逗号后最多得到2位数字。如果2.7表示为2.6999999999999999852,则仍会打印2.7,因为这是距离2.6999999999999999852最接近的2位逗号后字符串表示形式。

  2. 如果您想保证精度(通常在赚钱时是个好主意!),请勿完全使用double或float 。通常用钱解决的方法是使用intlong并存储美分而不是欧元或美元。有人会建议您改用BigDecimal,但我建议您不要这样做,除非您真的知道自己需要它。划分资金是很棘手的,并且需要一种自定义策略,即使BigDecimal也不能将4美分分配给3个银行帐户,而不能四舍五入或崩溃。如果您需要乘以详细信息,BigDecimal是一个更合理的想法,这会带来很多外汇。在您的情况下,需要应用增值税计算时,请不要理会并坚持使用以整数或多位存储的美分。

使用float而不是double时会得到不同结果的原因是,浮点数仅占用32位内存,因此float可以精确表示的数字更少,与double相对。 Java的System.out.println将应用四舍五入(但不多)。四舍五入往往不足以掩盖float的不准确性。

18.78998464050293是最能准确代表18.789984000000004实际答案的数字。