Toon posts:

[C#] Optellen doubles... vage output

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

Verwijderd

Topicstarter
Hey ppl,

Zit hier met vage output, misschien heeft 1 van jullie een verklaring:
Ik heb 2 double's gedeclareerd en gevuld met 1.1
nu tel ik dat op en denk 2.2 te krijgen.
Mooi niet dus.

Ik krijg 2.2000000011
(weet niet of ik precies ben met het aantal nullen)
Nu vraag ik me af; waar komt die 11 vandaan. Dit is gewoon stuk volgens mij.

Weet iemand een logische verklaring voor dit?
De help zegt niets over deze vage verschijnselen.

  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 10:01

gorgi_19

Kruimeltjes zijn weer op :9

Maak er eens decimals van

Zie ook: Alg/.NET Division by zero wordt niet afgevangen bij floats*

[ Voor 59% gewijzigd door gorgi_19 op 26-01-2004 17:04 ]

Digitaal onderwijsmateriaal, leermateriaal voor hbo


Verwijderd

Verwijderd schreef op 26 januari 2004 @ 17:02:

Nu vraag ik me af; waar komt die 11 vandaan. Dit is gewoon stuk volgens mij.
Dat restje is een bijverschijnsel van het binair opslaan van floating point getallen.

Verwijderd

Topicstarter
hmm... dan vraag ik me af waarom je dan in hemelsnaam een double zou gebruiken om te rekenen als 1 + 1 al niet 2 is met doubles
edit: Misschien is een doule wel niet geschapen om precies mee te rekenen...

[ Voor 24% gewijzigd door Verwijderd op 26-01-2004 17:24 ]


  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 25-09-2023
Omdat je:
- hele grote en kleine getallen hebt waarmee je wilt rekenen
- en dit rekenen ook nog snel moet gaan
- enig verlies van nauwkeurigheid daarbij niet uit te sluiten is (bijv: zoals Qlone al zei: er zijn decimalen die je niet met het formaat dat gekozen is voor floating-point getallen kan representeren met een eindige hoeveelheid bits, laat staan met minder dan 64).

Als dit een probleem is (bijvoorbeeld op financieel gebied), gebruik dan een speciaal daarvoor ontwikkeld datatype.

[ Voor 9% gewijzigd door Infinitive op 26-01-2004 17:29 ]

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]


  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 10:01

gorgi_19

Kruimeltjes zijn weer op :9

Verwijderd schreef op 26 januari 2004 @ 17:19:
hmm... dan vraag ik me af waarom je dan in hemelsnaam een double zou gebruiken om te rekenen als 1 + 1 al niet 2 is met doubles
edit: Misschien is een doule wel niet geschapen om precies mee te rekenen...
Range vna een double
The Double value type represents a double-precision 64-bit number with values ranging from negative 1.79769313486232e308 to positive 1.79769313486232e308, as well as positive or negative zero
Range van een Decimal
The Decimal value type represents decimal numbers ranging from positive 79,228,162,514,264,337,593,543,950,335 to negative 79,228,162,514,264,337,593,543,950,335. The Decimal value type is appropriate for financial calculations requiring large numbers of significant integral and fractional digits and no round-off errors
Ik denk dat je zelf wel het verschil kan zien... :) Ieder doel heeft z'n eigen nummer.

Digitaal onderwijsmateriaal, leermateriaal voor hbo


  • Rataplan
  • Registratie: Oktober 2001
  • Niet online

Rataplan

per aspera ad astra

Verwijderd schreef op 26 januari 2004 @ 17:19:
hmm... dan vraag ik me af waarom je dan in hemelsnaam een double zou gebruiken om te rekenen als 1 + 1 al niet 2 is met doubles
edit: Misschien is een doule wel niet geschapen om precies mee te rekenen...
Bij mij is 1.1+1.1 gewoon 2.2, welke resolutie ik ook bekijk. Welke versie? Doe je d'r verder nog iets mee? En heb je niet toevallig zo'n PIII met brakke FP-operaties?


Journalism is printing what someone else does not want printed; everything else is public relations.


  • ATS
  • Registratie: September 2001
  • Laatst online: 12-02 13:46

ATS

Het resultaat is weldegelijk correct in dit geval. Hoewel het bovenstaande over de beperkingen van doubles waar is, zijn de significante cijfers gewoon correct in je berekening: als je 1,1 + 1,1 doet, dan is het resultaat natuurlijk niet nauwkeuriger dan 2,2. 2,200 is al onzin, omdat je gegeven getallen niet zo precies waren. Zelfs 1 + 1,1 = 2,1 is onzin, het resultaat moet gewoon 2 zijn. De aanname dat 1=1,000000000 mag je niet zomaar doen. Alles meer dan wat je had aan nauwkeurigheid bij je begin getallen moet je negeren.

My opinions may have changed, but not the fact that I am right. -- Ashleigh Brilliant


Verwijderd

Topicstarter
Rataplan schreef op 26 januari 2004 @ 17:30:
[...]
Bij mij is 1.1+1.1 gewoon 2.2, welke resolutie ik ook bekijk. Welke versie? Doe je d'r verder nog iets mee? En heb je niet toevallig zo'n PIII met brakke FP-operaties?
Zat ik ook al aan te denken, maar ik heb hier een p4 2.4. met winxppro
ik heb .net 1.1 met c#
als ik debug of trace of string.format naar het scherm zie ik 2.2(met een zooitje nullen)11

hmm..vaag. maar ik gebruik voor dit stukje code wel decimals :)
double is niet bedoeld voor dit soort berekening kan ik uit de replies opmaken

  • Rataplan
  • Registratie: Oktober 2001
  • Niet online

Rataplan

per aspera ad astra

Verwijderd schreef op 26 januari 2004 @ 17:34:
Zat ik ook al aan te denken, maar ik heb hier een p4 2.4. met winxppro
Dat bugje zal in jouw processor idd wel opgelost zijn :D
als ik debug of trace of string.format naar het scherm zie ik 2.2(met een zooitje nullen)11
Misschien toch ff wat extra code doen. Decimals helpen, vast, maar
code:
1
2
3
4
double a = 1.1;
double b = 1.1;

MessageBox.Show((a + b).ToString("#.0000000000000000000000000000000"));
met nog drie keer zoveel nullen blijft 2.2 opleveren, en watches en locals en weet ik veel wat laten zich hier niet eens verleiden om nullen weer te geven. Ik neem dus even de vrijheid om te stellen dat je topicstart onvolledig is ;) Dat decimals het oplossen is mooi, maar als je elders een bug hebt, blijven je resultaten onbetrouwbaar...

[ Voor 4% gewijzigd door Rataplan op 26-01-2004 17:43 . Reden: nog een paar dozijn nullen verwijderd ten behoeve van de layout ]


Journalism is printing what someone else does not want printed; everything else is public relations.


  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 25-09-2023
hmm..vaag. maar ik gebruik voor dit stukje code wel decimals :)
double is niet bedoeld voor dit soort berekening kan ik uit de replies opmaken
Wat voor berekening wil je doen dat? Heb je echt die nauwkeurigheid wel nodig?

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]


Verwijderd

De reden dat het niet precies 2.2 is, is omdat 1.1 niet af te beelden is op een double, je kan 1.1 er niet precies in opslaan.

De reden is als volgt:

een doulbe werdt gecodeerd door een 64 bit woord. 1 bit is voor het teken (+ of -), een aantal bits voor het grondtal en een aantal bits voor de exponent. De waarde wordt dan als volgt berekend:

teken * grondtal * 2^exponent. Op deze manier is 1.1 niet te verkrijgen en zal je compiler de dichtstbijzijnde waarde kiezen die WEL afgebeeld kan worden, en dat zal iets van:

1.1000000000005 zijn ofzo.

Nou als de dat bij zichzelf optelt komt er dus ietsje meer dan 2.2 uit. Dit is dus het gevolg van het gebruik van doubles.

Engelse uitleg: http://www.nuvisionmiami....workbook/floating_tut.htm

[ Voor 6% gewijzigd door Verwijderd op 26-01-2004 19:22 ]


Verwijderd

Toch vraag ik me wel af wat de TS allemaal gedaan heeft...
C#:
1
2
3
4
5
6
            double a = 1.1;
            double b = 1.1;

            double c = a + b;

            System.Console.WriteLine(c);


Geeft als output toch wel '2.2' bij mij...

Maargoed... misschien is de 'precision' van de console output niet hoog genoeg?

[ Voor 18% gewijzigd door Verwijderd op 26-01-2004 23:28 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 04:03
Je kunt best als uitvoer 2,2 krijgen, maar dat komt dan door een gebrek aan nauwkeurigheid bij de weergave van je double. 2,2 is namelijk niet exact te representeren als een double; het is dus onmogelijk dat er daadwerkelijk 2,2 in een double variabele staat (net zoals het al onmogelijk was dat er exact 1,1 in stond). De uitleg van iLs verklaart waarom.

Doubles worden in het algemeen gebruikt voor berekeningen met 'natuurkundige' getallen, zoals het verwerken van meetgegevens (waar computers van oorsprong natuurlijk het meeste voor werden gebruikt). Daarbij heeft de invoer doorgaans al een beperkte precisie, dus is het niet erg als doubles geen exacte representatie van de getallen bevatten, zolang hun bereik maar groot genoeg is en er een beetje vlot mee te rekenen valt.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:51

.oisyn

Moderator Devschuur®

Demotivational Speaker

ATS schreef op 26 januari 2004 @ 17:33:
Het resultaat is weldegelijk correct in dit geval. Hoewel het bovenstaande over de beperkingen van doubles waar is, zijn de significante cijfers gewoon correct in je berekening: als je 1,1 + 1,1 doet, dan is het resultaat natuurlijk niet nauwkeuriger dan 2,2. 2,200 is al onzin, omdat je gegeven getallen niet zo precies waren. Zelfs 1 + 1,1 = 2,1 is onzin, het resultaat moet gewoon 2 zijn. De aanname dat 1=1,000000000 mag je niet zomaar doen. Alles meer dan wat je had aan nauwkeurigheid bij je begin getallen moet je negeren.
Dit is zo in de natuurkunde en scheikunde, waar men adhv meten aan waardes komt, die nooit exact bepaald kunnen worden (tenzij er geteld wordt natuurlijk, 3 appels + 11 appels is in de natuurkunde ook gewoon 14 appels en niet 1 * 101, de 3 en 11 zijn hier exacte telwaarden die niet af kunnen wijken.)

Wiskunde is daarentegen wel altijd exact, en daarvoor gaat jouw stelling ook niet op. Het hangt dus nogal van de toepassing van de getallen af, en die toepassing is niet bepaald door de mensen die het floating point formaat verzonnen hebben



Aanvullig op de post van iLs

Een double heeft een 53 bits mantissa en een 10 bits exponent. Aangezien het opgeslagen getal altijd de vorm heeft van [teken] [mantissa] * 2[exponent], en de mantissa altijd een waarde in het bereik [1, 2> heeft (maw, het is iets als 1,03242384, waarbij de 1 voor de komma altijd vast staat), hoeft die 1 natuurlijk niet te worden opgeslagen. Maar de mantissa krijgt hierdoor wel een effectieve precisie van 54 bits

Welnu, 1.1 opslaan in 54 bits past gewoon niet. Sterker nog, het kan sowieso niet met een eindig aantal bits

Laten we de 1.1 eens even om gaan zetten naar een binaire representatie. De 1 hebben we natuurlijk al, dus nu moeten we 0.1 nog krijgen. Dat doen we als volgt:
• Kijk of het getal groter gelijk aan 1, zo ja: schrijf een 1 neer, en trek 1 van het getal af. Zo nee: schrijf een 0 neer. Als het getal 0 is stop dan
• Vermenigvuldig het getal met 2


0.1 -> 0
0.2 -> 0
0.4 -> 0
0.8 -> 0
1.6 -> 1 -> 0.6
1.2 -> 1 -> 0.2
0.4 -> 0
0.8 -> 0
1.6 -> 1
1.2 -> 1 -> 0.2
0.4 -> 0
.
.

Het lijkt me duidelijk dat dit een herhalend patroon is. Steeds kom je weer op 0.4 terecht, en dit blijft oneindig lang doorgaan. Conclusie: het getal is niet binair te representeren, met wat voor precisie dan ook

1.1 in binair wordt dus 1.000011001100110011001100110011001100110011...

[ Voor 4% gewijzigd door .oisyn op 27-01-2004 00:55 ]

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.

Pagina: 1