-1

My Code goes as follows:

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 );

}

}

The current output is:

Verkoopprijs exclusief BTW: 17.726400604248045

Verkoopprijs inclusief 6% BTW: 18.78998464050293

Verkoopprijs inclusief 21% BTW: 21.448944731140134

But the code messes up the last couple decimal places in the output. The actual output for 6% should be: 18.789984000000004. What is wrong with my code?

I have tried swtiching from float to int and double, but none of them have worked for me.

JJT
  • 186
  • 1
  • 13
Sifu Duck
  • 23
  • 7
  • But I have tried to use it without float aswell, but when I swap float for double, the total decimals decline and it'll give like 4 or less decimals – Sifu Duck Sep 11 '18 at 12:37
  • Do you really understand what this link is telling you? Or to be more constructive: what do you think that link is telling you? Do you understand how floating point math / binary representation work out? – GhostCat Sep 11 '18 at 12:40
  • Sorry if i came over like that, I'm a beginner in programming and frankly I don't understand what they're saying, especially since im not a fluent english speaker aswell, apologies! – Sifu Duck Sep 11 '18 at 12:45

1 Answers1

2

Computers aren't magic. They cannot represent numbers at infinite precision as that would require infinite memory which doesn't exist. They use a creative solution to try to represent floating point numbers in a way that covers most numbers you'd care to represent whilst it all still fits in 32 bits (float) or 64 bits (double). But it does mean it's inexact. There are only a finite amount of specific numbers that a double/float can actually represent, and if you try to make one represent a number that isn't one of those, you instead get the number it CAN represent which is closest to it.

So, which numbers can and cannot be represented? That's very tricky because computers work in base 2 and us humans tend to think in base 10.

This leads to two important lessons:

  1. Whenever you 'render' a double or float, that is, show it to the user or convert it to a string for any other reason, you MUST specify to the computer what you're lookin for. "Just print it" will not do, and if you try that (for example, with System.out.println(someDouble); the computer just guesses and usually guesses wrong. Here's how to do it right: System.out.printf("%.2f\n", someDouble) or if you don't want to print but convert to a string, String.format("%.2f", someDouble): You're telling java to print/stringify it such that you get at most 2 digits after the comma. If 2.7 is represented as 2.6999999999999999852, it'll still print 2.7, because that's the closest no-more-than-2-digits-after-the-comma string representation to 2.6999999999999999852.

  2. If you wish to guarantee precision (usually a good idea when working with money!!), do not use double or float at all. The usual solution with money is to use int or long and store cents instead of euros or dollars. Some would suggest you use BigDecimal instead but I'd advise against that unless you really know you need it. Dividing money is tricky and requires a custom strategy, and even BigDecimal cannot divide 4 cents across 3 bank accounts without either rounding or crashing. BigDecimal is a more reasonable idea when you have to multiply by detailed, which comes up with foreign exchange a lot. In your case, where you need to apply VAT calculations, don't bother with it and stick with cents, stored in ints or longs.

The reason you get different results when using float instead of double is that floats take up only 32 bits of memory and therefore there are fewer numbers that are exactly representable by a float, versus double. Java's System.out.println will apply some rounding (but not much). That rounding tends to be insufficient to hide the inaccuracies of float.

18.78998464050293 is the nearest number that is exactly representable to the actual answer of 18.789984000000004.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • I think I kind of understand it now, is there a possibility that the outcome will change depending on the amount of math problems it solves, for example, I used "double inclusiefBtwLaag = (verkoopPrijs / 100) * BTW_LAAG + verkoopPrijs;" Would it be more accurate if i wrote, "double inclusiefBtwLaag = verkoopPrijs *1,06;" ? – Sifu Duck Sep 11 '18 at 13:11
  • asking cause my friend made the same code, and the inaccuracies that are shwoing in my code aren't showing in his, so I'm confused as to what might be the problem. – Sifu Duck Sep 11 '18 at 13:13
  • @MatthewLeonhart if your friend gets a different result then your and his code are not exactly the same; it would be interesting to compare your code and see what you are doing differently. – Jesper Sep 11 '18 at 14:15
  • @Jesper Fixed it, apparently I had to drop the "Divide by 100 and then multiply by 21" and had to swap that with an already calculated amount aka "1.21", the inaccuracy then fixed itself! – Sifu Duck Sep 11 '18 at 21:01