[js] floating points

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

Anoniem: 9542

Topicstarter
JavaScript:
1
alert(0.2+0.4);
levert 0.60000000000001

terwijl volgens mij de floating points toch exact binair zijn uit te drukken. Natuurlijk geen onbekend probleem en het levert nog wel wat hits op, maar nergens een goede oplossing. toFixed gaat me niet helpen, of in ieder geval niet direct, aangezien ik niet weet hoeveel decimale getallen er moeten zijn (het moet ook werken met 0.02+0.04 bijvoorbeeld)

Wat ik wil is de juiste waarde van de som, of tenminste de dichtst bijzijnde representeerbare waarde. 0.6 is volgens mij prima te representeren

Ik heb ook geen idee waar het probleem eigenlijk ligt, het is niet echt een overflow issue lijkt me, of een niet representeerbaar getal.

kan iemand verheldering verschaffen in de oorzaak hiervan? misschien komen we dan op een oplossing

Edit: eerste denkfout van mij: exponent is niet base 10, maar base 2 natuurlijk. Dus 0.2, 0.4 en 0.6 zijn niet exact representeerbaar. Dus bron van het probleem lijkt me daar te liggen.

[ Voor 10% gewijzigd door Anoniem: 9542 op 08-10-2007 14:30 ]


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 04-07 23:19
Jep, dit ligt dus wel aan het binair uitdrukkken van de floating points. De 0,2; 0,4; of 0,6 is niet exact binair uit te drukken. Dit is een bekend probleem. Je kunt er eigenlijk niet zo gek veel aan doen, probeer er op een creatieve manier omheen te werken.

[ Voor 24% gewijzigd door storeman op 08-10-2007 14:29 ]

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

Anoniem: 26306

Anoniem: 9542 schreef op maandag 08 oktober 2007 @ 14:26:
... aangezien ik niet weet hoeveel decimale getallen er moeten zijn ...
Dan heb je sowieso een probleem. Als het er 1, 2, 5 of 100 moeten kunnen zijn ga je toch tegen de limiet aanlopen. Als het bijvoorbeeld nooit meer dan 6 getallen na de komma mogen zijn, kun je integers gebruiken en dan delen door een miljoen.

Dit is niet een Javascript issue, maar een algemeen programmeerprobleem.

Acties:
  • 0 Henk 'm!

  • RM-rf
  • Registratie: September 2000
  • Laatst online: 12:40

RM-rf

1 2 3 4 5 7 6 8 9

Het ligt eraan dat Float nummers nooit bedoeld zijn om 'precies' de genoemde waarde te bevatten en bij berekeningen er altijd vanuitgaan dat enkel het getal tot het aangegeven aantal cijfers achter de komma klopt...
De reden was juist om berekeningen met erg lange cijferreeksen efficienter te maken (MegaFlops)

http://en.wikipedia.org/w...blems_with_floating-point

wil je eigenlijk een rekenwijze zoals die met 'Real' getallen gaat, maar dan tot op een getal achter de komma, kun je beter geen Float gebruiken maar een gewoon NUmber en die direkt voor de uitpunt bv door 100 delen om een getal van twee cijfers achter de komma te krijgen

Intelligente mensen zoeken in tijden van crisis naar oplossingen, Idioten zoeken dan schuldigen


Acties:
  • 0 Henk 'm!

Anoniem: 9542

Topicstarter
daar heb je toFixed voor, maar hoe ga ik weten tot hoeveel cijfers achter de komma ik nodig heb?

Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Anoniem: 9542 schreef op maandag 08 oktober 2007 @ 14:37:
daar heb je toFixed voor, maar hoe ga ik weten tot hoeveel cijfers achter de komma ik nodig heb?
Op een ranzige manier door float->string en string.length van substring (allesAchterKomma) te doen? :X

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Anoniem: 9542 schreef op maandag 08 oktober 2007 @ 14:37:
daar heb je toFixed voor, maar hoe ga ik weten tot hoeveel cijfers achter de komma ik nodig heb?
Je moet gewoon rekenen met je floats en pas afronden (op het moment dat je je resultaat nodig hebt) op het aantal gewenste decimalen.
mithras schreef op maandag 08 oktober 2007 @ 14:42:
[...]
Op een ranzige manier door float->string en string.length van substring (allesAchterKomma) te doen? :X
Dan nog altijd gewoon (bijv. voor 2 decimalen) vermenigvuldigen met 100, daar de int van pakken en dan weer delen door 100 ;) Voor 3 decimalen neem je dan 1000 uiteraard ;)

[ Voor 36% gewijzigd door RobIII op 08-10-2007 14:44 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
RobIII schreef op maandag 08 oktober 2007 @ 14:43:
[...]

Je moet gewoon rekenen met je floats en pas afronden (op het moment dat je je resultaat nodig hebt) op het aantal gewenste decimalen.
Dat is toch de crux van mophors verhaal? Als je 0.2+0.04 doet wil je afronden op 2 decimalen. 0.2 + 0.4 zal het aantal decimalen maar 1 zijn. Uiteraard rond je aan het einde pas af (dat lijkt me erg logisch), maar tot de hoeveelste decimaal?
[...]

Dan nog altijd gewoon (bijv. voor 2 decimalen) vermenigvuldigen met 100, daar de int van pakken en dan weer delen door 100 ;) Voor 3 decimalen neem je dan 1000 uiteraard ;)
En hoe komt javascript dan aan die "2" (of 100 dus), of "3" (de 1000)?

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
mithras schreef op maandag 08 oktober 2007 @ 14:47:
[...]
Dat is toch de crux van mophors verhaal?
Ja, dat haal ik er nu ook (pas) uit :P

[ Voor 34% gewijzigd door RobIII op 08-10-2007 14:48 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

Anoniem: 9542

Topicstarter
mja, heb nu even dit gedaan:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
rk.parseFloat = function(str) {
    var res = str.match(/^(-?)(\d+)(\.(\d+))?(e((-?)(\d+)))?$/);
    if (res===null) return NaN;
    var data = {
        isNegative: (res[1]==='-'),
        integer: res[2],
        hasDecimals: (res[3]!==''),
        numberOfDecimals: (res[4])?res[4].length:0,
        decimals: res[4],
        hasExponent: (res[5]!==''),
        exponent: res[6],
        exponentNegative: (res[7]==='-'),
        exponentInteger: res[8]||0,
        precision: ((parseInt(res[6],10)||0) + (res[4])?res[4].length:0)
    };
    data.valueOf = function(){return parseFloat(str);};
    data.toString = function(){return str;};
    return data;
};

een eigen parseFloat dus, die wat extra dingen opslaat. Aangezien het alleen maar om optellen en aftrekken (van getallen) gaat, kan ik daar dus de gewenste precisie uit halen

[ Voor 11% gewijzigd door Anoniem: 9542 op 08-10-2007 15:13 ]


Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

De oplossing is vrij eenvoudig. Veel programmeer talen hebben een constante voor Epsilon. Het 'maximale' verschillen tussen twee gelijkwaardige getallen. Javascript heeft deze constante helaas niet.
JavaScript:
1
2
3
4
5
epsilon = 0.000000001;
if (1/3 - 0.3333333 < epsilon)
    alert('Numbers are equal');
else
    alert('Not equal');


In bovenstaand voorbeel zou de vergelijking (1/3 == 0.333333) false hebben opgelevert. Echter door met behulp van epsilon te controleren of de afwijking binnen de marge valt is hierom heen te werken.

Het hoe en waarom van epsilon kun je hier lezen

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 03-07 11:38

Janoz

Moderator Devschuur®

!litemod

Significantie is redelijk makkelijk te bepalen als je ook de significantie van de input getallen weet. Bij optellen en aftrekken is de significantie bijvoorbeeld het minste aantal significante cijfers achter de komma van beide getallen en bij vermenigvuldigen gaat het over het totaal aantal significante cijfers (achter, maar ook voor de komma). Deze regels gaan vooral op voor gemeten waarden. Als je het over exacte waarden hebt, zoals geld, kun je soms beter fixedpoint getallen gebruiken. Zeker geld moet je in principe nooit met floating point getallen behandelen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

Anoniem: 9542

Topicstarter
is er (in andere talen) een datatype dat er voor zorgt dat getallen worden opgeslagen op een scientific manier? dus als integer, een optionele reeks decimalen en een exponent (base 10).

Ik zit er sterk over te denken om een eigen datatype te maken, met z'n eigen methods voor optellen enzo. Als ik er voor zorg dat significantie behouden blijft, door met strings te blijven werken, moet dit arbitrair grote getallen aankunnen significant kunnen rekenen (als het bij optellen, aftrekken en vermenigvuldigen blijft)

Nu ken ik zo'n representatie niet, maar als er zoiets is zou ik natuurlijk graag bestaande conventies aanhouden

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 03-07 11:38

Janoz

Moderator Devschuur®

!litemod

Java en Ruby hebben een BigDecimal. Java en C# hebben een BigInteger. Andere talen zullen vergelijkbare constructies hebben vermoed ik.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'

Pagina: 1