Avatar billede denser80 Nybegynder
12. maj 2007 - 17:25 Der er 17 kommentarer og
1 løsning

Fysikens love bryder sammen :-D

Jeg skulle lige lave en hurtig test på Number() funktionen og skrev et simpelt script der lyder:

var txt = "11.05";
var floatval = Number( txt );
window.alert( floatval - 1 );

vinduet der popper op siger 'selvfølgelig' "10.05", for dét er trods alt regnestykkets resultat.
MEN så var det at jeg rettede scriptet til at sige:

var txt = "11.05";
var floatval = Number( txt );
window.alert( floatval - 4 );

Og nu kan den pludselig ikke regne .. hér er hvad den påstår 11.05 - 4 er ..: 7.050000000000001 !!
Beder jeg den om at trække 8 fra bliver resultatet 3.0500000000000007  ... værre og værre. Jeg vil hermed gerne have fysik-lærebøgerne omskrevet, for tilsyneladende KAN man få noget ud af intet ;-)
Nogen der kan sige noget om hvad der foregår siden så simpel matematik slår fejl?
Avatar billede plx Nybegynder
12. maj 2007 - 17:32 #1
Avatar billede arne_v Ekspert
12. maj 2007 - 17:33 #2
calculations with floating points are simply not exact - if you need exact math
use something else than floating point
Avatar billede erikjacobsen Ekspert
12. maj 2007 - 18:33 #3
Du kan lave en afrunding til fx 2 decimaler når viser resultatet
Avatar billede denser80 Nybegynder
12. maj 2007 - 20:53 #4
Ja det er ikke fordi det er et problem som sådan at omgåes, jeg undrer mig bare over at min computer -eller JSP parseren- ikke kan regne :-D
Men betyder det at jeg generelt skal lave én beregning på heltallene, én på decimalerne, og ud fra de to beregne det faktiske resultat, frem for at lave beregninger af den type direkte i javascript? Hvor svært kan 11.05-4 være? ;-)
Avatar billede erikjacobsen Ekspert
12. maj 2007 - 21:25 #5
Det er faktisk svært, for du kan ikke skrive 0.05 som en sum af 0 eller 1 halv, 0 eller 1 kvart, 0 eller 1 ottendel, osv, svarende til de bits der står i din computer for kommadelen (og med et endeligt antal bits).

De 2 anbefalinger du har fået er at regne på heltal  1105-400 og skrive ud med komma det rette sted. Eller regne som nu, men udskrive afrundet.
Avatar billede crazysnap Seniormester
12. maj 2007 - 21:51 #6
Hej denser80,


Ja hvor svært kan det være! ;)

Nu får du hele smøren.

Det hele bunder i hvordan maskinen (hardwaren) repræsenterer de reelle og rationale tal. De fleste maskiner i dag implementerer IEEE 754 standarden hvor en float eller double repræsenteres ud fra en sign-bit, en significand og en exponent:

(-1)^sign * (significand) * 2^exponent


en float har 8 bits til exponenten, 23 bits til significanden og 1 bit til sign'et.


f.eks repræsenteres 0.1 som float:


sign bit: 0
significand: 1001 1001 1001 1001 1001 101
exponent: 0111 1011


Fordi der kun er et begrænset antal bits til at gemme de forskellige reelle og rationalle tal er det langt fra alle tal som kan repræsenteres på maskinen som en float eller double. Og det er netop her sådanne fejl som du får ovenover popper frem.

For hver aritmetisk operation du udfører mellem to floats eller doubles kan der opstå afrundingsfejl hvis resultatet (eller mellem-resultaterne) ikke kan repræsenteres ved hjælp af de begrænsede antal bits og den formel ovenover. Det er så dog muligt at implementere en arbitrær præcisions datatype som giver eksakte resultater, datatypen bliver så desværre ca. 100 gange langsommere til at udføre aritmetiske operationer end ved normale hardware operationer.

De her datatyper er selvfølgelig ikke helt trivielle at implementere men der eksiterer mange biblioteker derude som indeholder datatyperne, f.eks. GMP, LEDA, CGAL eller CORE. Java har også en BigDouble datatype med arbitrær præcision.

Så det betyder det intet med javascript har at gøre, du kan bare ikke regne med at dine resultater bliver helt eksakte når du bruger en floating-point datatype. Det er derfor også helt vitalt at alt software til banker osv bruger datatyper med arbitrær præcision, ellers kunne vi ikke være sikre på at beløbet på vores konti var det eksakte beløb. ;)


Så hvis du vil have eksakte resultater uden brug af arbitrær præcisions datatyper må du udføre heltalsberegninger (int). :)


Mvh.

- Snap :)
Avatar billede roenving Novice
12. maj 2007 - 23:37 #7
>>crazy

-- er exponenten i dit eksempel en little eller big endian ?-)

-- for umiddelbart kan jeg ikke gennemskue, hvordan man kan få et tal under en, hvis eksponenten er 123, altså positiv ...

-- hvis bits derimod aflæses omvendt gruppevis, giver det fint mening, da det så er en negativ eksponent !-)
Avatar billede erikjacobsen Ekspert
12. maj 2007 - 23:40 #8
Exponenten er i "Excess 128"-repræsentation. Google er din ven ;)
Avatar billede denser80 Nybegynder
12. maj 2007 - 23:42 #9
jaja, så blev man da dét klogere :) Syntes stadig der er lidt overraskende at en sådan ekstra implementering af biblioteker for præcise beregninger er påkrævet. Sådan i betragtning af at beregninger li'som er hvad en computer gør :-D
Avatar billede roenving Novice
13. maj 2007 - 00:18 #10
Tjah, de 127 havde jeg ikke lige set ...
Avatar billede crazysnap Seniormester
13. maj 2007 - 00:35 #11
>> roenving

Ja exponenten er bias'ed, dvs ved float skal der trækkes en bias på 127 fra eksponenten (1023 for doubles) og dermed har du dine negative eksponenter og dermed dine tal under 1. :)


Hvad endian angår er det forskelligt fra hardware til hardware om floaten er repræsenteret ved little eller big endian formen. :)


Mvh.

- Snap
Avatar billede denser80 Nybegynder
13. maj 2007 - 01:42 #12
Jeg skal lige have på det rene ... det hér JSP er jo kun på clientsiden, og hér skal der ikke foregå nogen nævneværdig beregning, omend ".05" problemet sagtens kan opstå .. altså hvis jeg ikke deler beregningen op, hvilket jeg selvfølgelig gør ;)
Men hvad så når tallene er sendt til serveren, lagt i database og sidenhen skal bruges i beregninger .. skal jeg så også i PHP være opmærksom på dette?
Syntes stadig det er lidt spøjst at man skal tage særskilt hensyn til det i JSP.
Avatar billede roenving Novice
13. maj 2007 - 01:57 #13
JSP er helt misforstået, for det betyder Java Server Pages og er en arkitektur, der benytter Java til at lave dynamiske websider fra en server, så det har ikke det fjerneste med klienten at gøre ...

Typisk vil man benytte javascript på klienten for at udføre noget dynamisk, men javascript og Java har cirka 4 ting til fælles:
j - a - v - a !-)

-- og php bruger præcis den samme måde at beregne på, men har så en hel del flere funktioner indbygget, så der kan du finde en round-funktion, der direkte kan afrunde et tal til et bestemt antal decimaler, hvis du skal bruge en sådan i javascript, skal du skrive eller hente den selv !o]
Avatar billede roenving Novice
13. maj 2007 - 02:14 #14
I øvrigt: tak for henvisningerne til floating point-fortolkningen !-)
Avatar billede crazysnap Seniormester
13. maj 2007 - 11:39 #15
Hej denser80,


Som jeg også skrev tidligere så har afrundingsfejlene ved floating-point aritmetik intet med script eller programmeringssprog at gøre. Fejlene opstår i hardwaren når der afrundens til et tal maskinen kan repræsentere. Det betyder at når du gemmer en eksakt værdi (udregnet i heltal i javascript) i databasen som en float eller double sker der allerede en afrundingsfejl i konverteringen (for at tallet kan gemmes). Så næste gang du hiver talet ud af databasen kan du ikke regne med det er eksakt mere.

Dette fænomen er noget alle programmører må døje med i ALLE sprog, men i de fleste tilfælde har vi ikke brug for eksakte resultater (fejlene er jo meget små), det er kun når vi involverer penge eller f.eks. EGC (exact geometry computation) det bliver et problem. Altså når man f.eks. skal finde skæringspunkter mellem to eller flere trekanter, i sådanne tilfælde kan der nemlig opstå tvetydigheder mellem trekanternes skæringspunkter der i værste tilfælde kan få algoritmen til at fejle.


Jeg vil da råde alle programmører som ikke kender til afrundingsproblemet for floating points til at læse mere om emnet så man ihvertfald er klar over begrænsningerne. :) Et godt sted at starte er:

www.physics.ohio-state.edu/~dws/grouplinks/floating_point_math.pdf

Eller den gamle udgave af documentet skrevet af David Goldberg (jeg har ikke læst den nye udgave som jeg refererer til ovenover, men læste den gamle under studietiden).


Og denser80, for at sikre at dine resultater forbliver eksakte (hvis det er meget vigtigt) kan du f.eks. gemme din tal som opsplittede integers i databasen? Eller som roenving foreslår, "gemme" fejlen lidt ved at afrunde til f.eks. 2 decimaler. :)


Mvh.

- Snap :)
Avatar billede denser80 Nybegynder
13. maj 2007 - 23:55 #16
roenvig: "JSP er helt misforstået, for det betyder Java Server Pages og er ... "
det var jeg egentlig godt klar over :) det er bare blevet en 'dårlig' vane med P'et til sidst ;)

crazysnap: Som sådan er jeg godt klar over .. nu :) hvor 'fejlen' er, og jeg kan til dels forstå det med beregninger på polygoner osv. som du siger, men ... ja jeg er stadig bare lidt overrasket over at sådan fejl er så nem at fremprovokere.
Selvom javascript ikke er tænkt som et highlevel techno sprog.
Men ja .. så har jeg da lært dét ;-D
Så mangler der bare at javascript kan manipulere tyngdeaccelerationen .. jeg mener ... når nu man kan få noget for intet ;-)
Avatar billede denser80 Nybegynder
16. maj 2007 - 15:03 #17
crazysnap: smider du et svar så jeg kan belønne dine uddybende kommentarer? :)
Avatar billede crazysnap Seniormester
16. maj 2007 - 15:10 #18
Hej denser80,


Ja, her har du et svar og held og lykke med det! :)


Mvh.

- Snap
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester