[JAVA] Integer getal als geldbedrag weergeven

Pagina: 1
Acties:
  • 544 views sinds 30-01-2008
  • Reageer

  • qrazi
  • Registratie: Oktober 2000
  • Laatst online: 29-11 12:28
Ten eerste, ik weet niet zeker of dit het juiste forum is.

Ik ben bezig om het boek "En dan is er... Java" door te werken. Ik ben nu al een paar keer opgaven tegen gekomen waarbij het het netste is om met integer getallen te rekenen, maar waarbij de output eigenlijk op twee decimalen moet eindigen. Dit is dan natuurlijk mbt geld bedragen.

Stel dat ik het integer getal 6750 heb, en dit eigenlijk 67,50 EUR betekend. Hoe maak ik hier dan een output van 67,50?

als ik bijvoorbeeld doe:

Java:
1
totaal = (double) temp / 100;


is totaal een getal 67.5, en niet 67.50. Misschien zie ik het gewoon niet, misschien moet ik nog wat meer hoofdstukken doorwerken (ben nu bij hoofdstuk 6). Wellicht heeft iemand een simpel antwoord voor een beginner.

[ Voor 0% gewijzigd door qrazi op 19-02-2007 23:49 . Reden: typo ]

AMD Phenom II X2 555@ X4 B55, 4GB DDR3-1333 OCZ Gold, MSI 870A-G54, Radeon HD 7770 512 MB


  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

Geen supergoed boek dat, maar goed. Dit kun je doen met MessageFormat (of NumberFormat).

All my posts are provided as-is. They come with NO WARRANTY at all.


  • Snake
  • Registratie: Juli 2005
  • Laatst online: 07-03-2024

Snake

Los Angeles, CA, USA

Waarom zou je een komma getal opslaan als integer? Als je dan nog toevallig achter de komma uitkomt, dan ben je dat kwijt?

Daarvoor is er float/double he!

Going for adventure, lots of sun and a convertible! | GMT-8


Verwijderd

Snakiej schreef op maandag 19 februari 2007 @ 23:51:
Waarom zou je een komma getal opslaan als integer? Als je dan nog toevallig achter de komma uitkomt, dan ben je dat kwijt?

Daarvoor is er float/double he!
Omdat er genoeg bedrijven zijn die in centen werken op hun oude warehouses.

  • momania
  • Registratie: Mei 2000
  • Laatst online: 05:21

momania

iPhone 30! Bam!

Als je 67,50 wilt hebben moet je dat ook gebruiken en niet vermommen als een 6750 int ;)

Voor formatting kan je de (hoe toepasselijke naam ook ;) ) de NumberFormat gebruiken en dan wel in de implementatie van de DecimalFormat.

Java:
1
2
3
double amount = 67.5;
NumberFormat format = new DecimalFormat("#.##0,00");
System.out.println(format.format(amount));

Moet '67,50' als output geven :Y)
http://java.sun.com/j2se/...a/text/DecimalFormat.html

Neem je whisky mee, is het te weinig... *zucht*


  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

floats en doubles zijn heel slecht voor geld.

All my posts are provided as-is. They come with NO WARRANTY at all.


  • GlowMouse
  • Registratie: November 2002
  • Niet online
CyBeR schreef op maandag 19 februari 2007 @ 23:56:
floats en doubles zijn heel slecht voor geld.
Inderdaad. Zie laatst dit topic waar het verschil van twee identieke bedragen niet 0 maar 10-14 was door afrondingsfouten.

  • Snake
  • Registratie: Juli 2005
  • Laatst online: 07-03-2024

Snake

Los Angeles, CA, USA

Verwijderd schreef op maandag 19 februari 2007 @ 23:53:
[...]


Omdat er genoeg bedrijven zijn die in centen werken op hun oude warehouses.
En dat is?
GlowMouse schreef op maandag 19 februari 2007 @ 23:59:
[...]

Inderdaad. Zie laatst dit topic waar het verschil van twee identieke bedragen niet 0 maar 10-14 was door afrondingsfouten.
Wat dan gebruiken? BigDecimal?

Going for adventure, lots of sun and a convertible! | GMT-8


  • Marcj
  • Registratie: November 2000
  • Laatst online: 12:49
Snakiej schreef op dinsdag 20 februari 2007 @ 00:10:
[...]

En dat is?
[...]

Wat dan gebruiken? BigDecimal?
BigDecimal is een optie, maar weet je wat die intern gebruikt? Een array van integers :) (of bytes kan ook). Voor precisie moet je toch echt met integers gaan werken. Dan kun je nooit problemen krijgen met afrondingen. Moet je alleen voor jezelf bepalen hoeveel cijfers achter de komma je nodig bent, maar meestal voldoet 2 cijfers wel. Dan reken je dus gewoon in centen. Waarom moet dit lastig zijn dan? Je moet alleen rekening er mee houden dat alles achter deze 2 cijfers wordt genegeerd. Maar dat is nog altijd beter dan met floats werken waar je problemen krijgt zoals in het vorige topic.

Verwijderd

De denkfout is dat het om een floating point (dus niet-geheel) getal zou gaan. Als je kleinste eenheid een cent is (en je dus niet met tienden of honderdsten van een cent werkt), werkt je FEITELIJK met gehele getallen, dus integers. Je hebt het dan namelijk altijd over een geheel aantal centen. Het feit dat je bij het afdrukken ergens een komma zet, maakt daarbij niets uit. Er is geen goede reden om een floating point te nemen als je het in werkelijkheid hebt over een grootheid die alleen maar gehele waarden aanneemt.

  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Stop valuta's waarmee je wilt gaan rekenen inderdaad bij voorkeur in een BigDecimal :)

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Marcj schreef op dinsdag 20 februari 2007 @ 00:22:
[...]

BigDecimal is een optie, maar weet je wat die intern gebruikt? Een array van integers :) (of bytes kan ook). Voor precisie moet je toch echt met integers gaan werken. Dan kun je nooit problemen krijgen met afrondingen. Moet je alleen voor jezelf bepalen hoeveel cijfers achter de komma je nodig bent, maar meestal voldoet 2 cijfers wel. Dan reken je dus gewoon in centen. Waarom moet dit lastig zijn dan? Je moet alleen rekening er mee houden dat alles achter deze 2 cijfers wordt genegeerd. Maar dat is nog altijd beter dan met floats werken waar je problemen krijgt zoals in het vorige topic.
Of ik lees het verkeerd, of je spreekt jezelf volgens mij tegen. Juist OMDAT BigDecimal intern met ints werkt, is het een goede keuze, zeker omdat je dan alle voordelen van de BigDecimal API hebt en misschien nog handiger, je niet zelf de preciezie bij hoeft te houden.

Fat Pizza's pizza, they are big and they are cheezy


  • momania
  • Registratie: Mei 2000
  • Laatst online: 05:21

momania

iPhone 30! Bam!

Verwijderd schreef op dinsdag 20 februari 2007 @ 00:49:
Er is geen goede reden om een floating point te nemen als je het in werkelijkheid hebt over een grootheid die alleen maar gehele waarden aanneemt.
Uhm, en hoe zit het dan met delen, wisselkoersen, etc? ;)

Neem je whisky mee, is het te weinig... *zucht*


  • qrazi
  • Registratie: Oktober 2000
  • Laatst online: 29-11 12:28
Er zijn vast wel slechtere boeken om Java te leren... :)

Ik ben van integer getallen uitgegaan omdat er dan inderdaad mooie ronde getallen uitkomen. Voor de berekeningen etc. ga ik dus uit van de bedragen in centen. Alleen wil je natuurlijk de output wel in euro's op het scherm hebben.

Ik zal vanavond kijken of ik uit de DecimalFormat kom.

AMD Phenom II X2 555@ X4 B55, 4GB DDR3-1333 OCZ Gold, MSI 870A-G54, Radeon HD 7770 512 MB


  • Marcj
  • Registratie: November 2000
  • Laatst online: 12:49
JKVA schreef op dinsdag 20 februari 2007 @ 07:02:
[...]

Of ik lees het verkeerd, of je spreekt jezelf volgens mij tegen. Juist OMDAT BigDecimal intern met ints werkt, is het een goede keuze, zeker omdat je dan alle voordelen van de BigDecimal API hebt en misschien nog handiger, je niet zelf de preciezie bij hoeft te houden.
Misschien staat het er niet duidelijk, maar ik probeer te zeggen dat BigDecimal ook een optie is, maar die is intern eigenlijk gelijk aan integer, omdat die ook met gehele getallen werkt. Je moet zelfs bij delingen opgeven tot hoeveel decimalen je wilt gaan.

Het enige nadeel van BigDecimal is dat het (in verhouding) veel meer geheugen en processorkracht vereist, maar dat is hier denk ik geen probleem :)

  • Nick The Heazk
  • Registratie: Maart 2004
  • Laatst online: 07-09-2024

Nick The Heazk

Zie jij er wat in?

Snakiej schreef op maandag 19 februari 2007 @ 23:51:
Waarom zou je een komma getal opslaan als integer? Als je dan nog toevallig achter de komma uitkomt, dan ben je dat kwijt?

Daarvoor is er float/double he!
Omdat bewerkingen met floating point getallen niet exact verlopen. Zo kan het zijn dat een kleine afwijking op de gegevens meteen voor een grote fout kan zorgen op het resultaat (de idee van numerieke conditie van een probleem, in combinatie met de numerieke stabiliteit van de gebruikte methode).

Je moet maar eens de volgende code uitvoeren om een - schrikwekkend - beeld te krijgen van floating point bewerkingen.

Java:
1
2
3
4
5
6
7
8
9
double one = 1.0;
double alsoOne = 0.0;
        
for(int i = 0; i < 10; i++)
    alsoOne += 0.1;
        
System.out.println(one);
System.out.println(alsoOne);
System.out.println(one == alsoOne);

Performance is a residue of good design.


  • rapture
  • Registratie: Februari 2004
  • Nu online

rapture

Zelfs daar netwerken?

Het probleem met floats/doubles, is dat je met binaire cijfers moeilijk getallen na de komma kan maken. Voor de komma gaat het gemakkelijk, machten van 2 en je kan allerlei grotere getallen maken. Maar na de komma heb je weer machten van 2, maar deze gaan naar beneden.
0,5 = 1*1/2
0,4 = 1/4+1/8+1/64+1/128+1/1024+1/2048+1/16384+1/32768+1/262144+1/524288+1/4194304+1/8388608 = 0,399999976158 (dit is een single precision floating point, met double wordt de fout wat kleiner, maar het blijft een fout)

De meeste kommagetallen worden vreselijke benaderingen, vreselijk genoeg om een Patriot luchtafweerinstallatie naast de Scuds te laten schieten, tijdens de Golfoorlog (1991). Zo zijn er Amerikaanse troepen gestorven wegens stomme kommafouten die continue opstapelden totdat het fataal ernaast schoot. Oplossing: Regelmatig de luchtafweer rebooten zodat de fouten niet te hard opstapelen. nieuws: Onderzoekers Sun vinden computers slecht rekenen

  • qrazi
  • Registratie: Oktober 2000
  • Laatst online: 29-11 12:28
Ik heb deze opgave maar als volgt afgerond. Nog steeds niet helemaal correct, omdat er in het geval van twee nullen achter de komma, slechts 1 nul weergeven wordt...

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//opgaven hoofdstuk 6
import java.awt.*;
import java.applet.*;
import java.awt.event.*;

public class opgave_6_04 extends Applet
{
  Button result;
  TextField veld;
  int prijs1, prijs2, totaal1, totaal2, prijstemp, totaaltemp;

  public void init() {
  result = new Button("Totaal");
  result.addActionListener( new ResultHandler() );
  veld = new TextField(3);

  add(veld);
  add(result);
  }

  public void paint( Graphics g ) {
  g.drawString("Prijs per pen: " + prijs1 + "," + prijs2, 30, 80 );
  g.drawString("Totaalprijs: " + totaal1 + "," + totaal2, 30, 110 );
  }

  class ResultHandler implements ActionListener {
    public void actionPerformed( ActionEvent e ) {
    String invoer = veld.getText();
    int a = Integer.parseInt( invoer );
    if ( a <= 9 && a >= 0 ) {
      prijstemp = 200;
      }
    else if ( a <= 49 && a >= 10 ) {
      prijstemp = 150;
      }
    else if ( a <= 99 && a >= 50 ) {
      prijstemp = 125;
      }
    else if( a >= 100 ) {
      prijstemp = 110;
      }
    totaaltemp = prijstemp * a;
    prijs1 = prijstemp / 100;
    prijs2 = prijstemp % 100;
    totaal1 = totaaltemp / 100;
    totaal2 = totaaltemp % 100;
    veld.setText("");
    repaint();
    }
  }
}


Leer het vast nog wel eens beter te doen...

AMD Phenom II X2 555@ X4 B55, 4GB DDR3-1333 OCZ Gold, MSI 870A-G54, Radeon HD 7770 512 MB


  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

Ik zie geen Numberformats en geen MessageFormats, waar ik je op gewezen had. Die hadden dat allebei goed gedaan.

All my posts are provided as-is. They come with NO WARRANTY at all.


  • Macros
  • Registratie: Februari 2000
  • Laatst online: 21-11 11:06

Macros

I'm watching...

Wij gebruiken altijd BigDecimals voor valuta's. Tijdens berekeningen houden we de scale op 5 en na de berekeningen ronden we af naar 2 decimalen (setScale(2)) De afronding zetten we op ROUND_HALF_EVEN. Hieronder een voorbeeldje van code dat perfect omgaat met bedragen en geen enkele cent kwijtraakt.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    private static final BigDecimal ZERO = new BigDecimal("0.00");

    /**
     * Calculate the amount without vat
     * excl = incl / ((percentage/100) + 1)
     * 
     * @param amountInclVat
     * @param percentage The Vat percentage (example: 19.00)
     * @return The amount without vat (amountExclVat)
     */
    public static BigDecimal calculateExclVat(BigDecimal amountInclVat,
            BigDecimal percentage) {
        if(amountInclVat.signum() < 0){
            throw new IllegalArgumentException("Can't calculate excl vat on a negative amount");
        }
        // check for percentage is removed, because it won't change that much
        return amountInclVat.divide(percentage.scaleByPowerOfTen(-2).add(
                BigDecimal.ONE), 2, BigDecimal.ROUND_HALF_EVEN);
    }
    
    /**
     * Calculate the amounts incl and excl vat and the Vat account. A paid amount can be passed which will be deducted
     * from the amounts as apropriate, starting with the exclVat and inclVat amounts, only if the paid amount is greater
     * than the exclVat amount, the vat will be deducted.
     * 
     * @param amountInclVat the amount including vat (eg. a total invoice amount)
     * @param paidAmount the amount paid, can be null or ZERO.
     */
    @Transient
    public VatAmounts calculateAmounts(BigDecimal amountInclVat, BigDecimal paidAmount) {
        BigDecimal invoiceAmountExcl = calculateExclVat(amountInclVat);
        BigDecimal invoiceAmountVat = amountInclVat.subtract(invoiceAmountExcl).setScale(5, BigDecimal.ROUND_HALF_EVEN);
        
        // Take already paid amounts into account:
        if (paidAmount != null && paidAmount.signum() > 0) {

            // if paid amount > total inc vat, the client should not be charged a negative amount
            if(paidAmount.compareTo(amountInclVat) >= 0){
                return new VatAmounts(ZERO, ZERO, ZERO);
            }
            
            invoiceAmountExcl = invoiceAmountExcl.subtract(paidAmount).setScale(5, BigDecimal.ROUND_HALF_EVEN);
            amountInclVat = amountInclVat.subtract(paidAmount).setScale(5, BigDecimal.ROUND_HALF_EVEN);
            
            if(invoiceAmountExcl.signum() < 0){ 
                // client paid off more than the excl amount
                invoiceAmountVat = invoiceAmountVat.add(invoiceAmountExcl).setScale(5, BigDecimal.ROUND_HALF_EVEN); // ex is neg
                invoiceAmountExcl = ZERO;
            }
        }

        amountInclVat = amountInclVat.setScale(2, BigDecimal.ROUND_HALF_EVEN);
        invoiceAmountExcl = invoiceAmountExcl.setScale(2, BigDecimal.ROUND_HALF_EVEN);
        invoiceAmountVat = invoiceAmountVat.setScale(2, BigDecimal.ROUND_HALF_EVEN);
        
        BigDecimal rest = amountInclVat.subtract(invoiceAmountExcl).subtract(invoiceAmountVat);
        if(rest.signum() != 0){
            invoiceAmountVat = invoiceAmountVat.add(rest);
        }
        
        return new VatAmounts(amountInclVat, invoiceAmountExcl, invoiceAmountVat);
    }

"Beauty is the ultimate defence against complexity." David Gelernter


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 12:37

.oisyn

Moderator Devschuur®

Demotivational Speaker

Een floating point getal is precies dat: een getal met een drijvende komma. Je wilt geen valuta's opslaan met een drijvende komma en een gelimiteerd aantal significante cijfers - het slaat nergens op dat je 0.000001 en 1000000 kunt opslaan, maar niet 100000.000001. Je wilt dus een type met een vaste komma ofwel fixed point. BigDecimal is zo'n fixed point type. Of je gebruikt een int en deelt/vermenigvuldigt handmatig met een bepaalde factor (100) bij in- en uitvoer.
momania schreef op dinsdag 20 februari 2007 @ 08:54:

Uhm, en hoe zit het dan met delen, wisselkoersen, etc? ;)
Zorgen dat je genoeg precisie hebt. Ik geloof dat banken met 6 cijfers achter de komma werken. En dus ook altijd 6, geen floating point getallen.

[ Voor 25% gewijzigd door .oisyn op 01-03-2007 17:23 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Klopt, 6 cijfers is de ECB standaard. En die leggt ook de afrond regels vast, dus de banken kunnen zelfs geen microeuros achterover drukken. Ik denk dat iedereen die hier vragen stelt dat mag negeren :)

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • momania
  • Registratie: Mei 2000
  • Laatst online: 05:21

momania

iPhone 30! Bam!

.oisyn schreef op donderdag 01 maart 2007 @ 17:21:
Zorgen dat je genoeg precisie hebt. Ik geloof dat banken met 6 cijfers achter de komma werken. En dus ook altijd 6, geen floating point getallen.
I know, programmeer al 7 jaar voor banken ;)
Was meer als reactie waarom je dan geen integers zou nemen etc.

Opslaan van bedragen gaat altijd met minimaal 6 decimalen idd. De berekeningen tussendoor gaan evengoed wel zonder afrondingen verder. :)

Neem je whisky mee, is het te weinig... *zucht*


  • Macros
  • Registratie: Februari 2000
  • Laatst online: 21-11 11:06

Macros

I'm watching...

Je kan niet zomaar integers gebruiken, omdat die altijd floor afronding gebruikt en dat wil je ook niet.

"Beauty is the ultimate defence against complexity." David Gelernter

Pagina: 1