Avatar billede madsen666 Nybegynder
20. juli 2001 - 09:46 Der er 12 kommentarer og
1 løsning

Mystik med doubles!

Hej!

Er der nogen der ved hvorfor jeg får 1.99999999993 og ikke 2 som output i følgende program:

#include <iostream>

void main(){
  double a=2.0;
  double b=2.0/2000000.0;
  double h=0.0;
  int i=0;
  while (i<2000000){
    h+=b;
    i++;
  }
  cout.precision(12);
  cout << h << \"\\n\";
}


Jeg har prøvet det på både en Celeron og en MIPS 12000 (med 12010 FPU) cpu, og bægge giver samme output.
Avatar billede karlkoder Nybegynder
20. juli 2001 - 10:46 #1
har det msåke noget med på præcisionen på en double at gøre ??

har du checktet indenfor et hvilket interval at en double kan være i ??
Avatar billede madsen666 Nybegynder
20. juli 2001 - 11:26 #2
I <float.h> kan man se DBL_DIG der er decimale cifre i repræsentationen. Denne er 15 på min celeron. b er i ovenstående 1e-6, dvs. der bliver brugt langt fra 15 cifre....
Avatar billede perboeggild Nybegynder
20. juli 2001 - 13:19 #3
Det må have noget at gøre med cout.precision. Hvis du prøver følgende:

#include <iostream>

void main(){
  double a=2.0;
  double b=2.0/2000000.0000;
  double h=0.0;
  int i=0;
  while (i<2000000){
    h+=b;
    i++;
    if (i % 100000 == 0)
      cout << h << \"\\n\";
  }
  cout.precision(12);
  cout << h << \"\\n\";
 
}

ser du, at det sidste output i løkken er 2. Jeg er ikke en meget erfaren programmør, så jeg kan ikke give dig svar på, hvorfor der bliver afrundet så mystisk med cout.precision
Avatar billede madsen666 Nybegynder
20. juli 2001 - 13:39 #4
Det er fordi, at den \"default\"\'e præsion på cout er 6 decimaler(ved mig ihvertfald, prøv at indsætte \"cout << cout.precision() << \"\\n\";\"). Dvs. med 6 decimaler er resultatet godt nok, hvilket vi ogsaa kan se ud fra resultatet med 12 decimaler. Men hvorfor resultatet ikke er rigtigt med 12 decimaler er liiiidt mærkelig.... (og uhyggeligt! Hvem vil sendes til månen af sådan en computer?)
Avatar billede madsen666 Nybegynder
20. juli 2001 - 13:45 #5
Lidt mere info.... Skriver man løkken ud med 15 decimaler får man:

0.100000000000079
0.200000000000179
0.299999999998892
0.399999999996216
0.49999999999354
0.599999999996416
0.699999999999292
0.800000000002167
0.900000000005043
1.00000000000792
1.09999999999969
1.19999999999146
1.29999999998324
1.39999999997501
1.49999999996678
1.59999999995856
1.69999999995033
1.7999999999421
1.89999999993388
1.99999999992565

Men skriver man b ud med 15 decimaler få man:

1e-6

hvilket jo er rigtigt nok. Kan computere ikke lægge flydendekomma-tal sammen eller hvad?
Avatar billede perboeggild Nybegynder
20. juli 2001 - 14:13 #6
Hvis jeg skriver b ud med 12 decimaler får jeg:

9.99999997475e-07

Jeg har engang fået en artikel i hånden:
\"What every computerscientist should know about floating point numbers\", men har desværre ikke læst den og kan ikke huske, hvor den er henne.

Jeg må give op!
Avatar billede haff Nybegynder
20. juli 2001 - 15:51 #7
Hej

Grunden til at du ikke får det resultat du forventer skyldes kunne skyldes at du til \'h\' lægger
\'b\' til 2000000 gange, dvs. den \'støj\' der ligger på den sidste decimaler i b bliver forstørret
2000000 gange, hvilket giver dig din manglende præsicion på 12. decimal

float og double
følger IEEE 754 standarden.
single precision (32 bit)(float)
eller
double precision (64 bit( (double)
i single precision er benyttes bit\'ne som følger:
1 bit repræsenterer fortegnet.
8 bit repræsenterer Exponenten
23 bit repræsentere Fraction - delen

i 64 bit:
1 bit fortegn
13 Exponenten
52 bit Fraction
dvs. den præcision du maks. kan opnå med float er
2^23 dvs. ca 6-7 betydende cifre.
en double er præcisionen
2^53 ca. 15 cifre

mvh
Anders
Avatar billede kamikaze Nybegynder
21. juli 2001 - 12:10 #8
haff >> Jamen, du skriver at man kan opnå 15 cifres præcision med en double, men madsen666\'s eksempel bruger doubles med 12 cifre, og er ikke præcist!?!?!?

Når jeg kompilerer eksemlet med præsition på 10, er resultatet rigtigt, men på 11 kommer der fejl!
Avatar billede haff Nybegynder
22. juli 2001 - 19:09 #9
Han forstørrer den usikkerhed der ligger på sidste ciffer ca. 2000000 gange, hvilket giver forkert decimal på 12. ciffer.

Prøv f.eks. i eksemplet at sætte
her vil du sikkert på rigtigt resultat på 12 ciffer. /haff
void main(){
  double a=2.0;
  double b=2.0/200.0;//
  double h=0.0;
  int i=0;
  while (i<200){
    h+=b;//
    i++;
  }
  cout.precision(12);
  cout << h << \"\\n\";
}



Avatar billede haff Nybegynder
22. juli 2001 - 20:03 #10
Okay
Løsningen er at heletiden holde styr på
antallet af betydende cifre!
Jeg har tilføjet en måske lidt banal
oprunding funktion, der sikre mig at jeg
en præcision på med 14 betydende ciffer.
her er hele koden.
//precision.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

double runb14(double bel);

void main()
{
  double a = 2.0;
  double b = 2.0/2000000.0;
  int i = 0;
  while(i<2000000)
  {
    h += b;
    h = runb14(h);
    i++;
  }
  printf(\"%0.15f\\n\",h);

}

double runb14(double bel)
{
  char buffer[100];
  int negativ = 0;
  if (bel<0)
  {
    bel = -bel;
    negativ = 1;
  }
  sprintf(buffer,\"0.14%f\",bel);
  bel = atof(double);
  if(negativ)
    bel = -bel;
  return bel;
}


/haff
Avatar billede haff Nybegynder
22. juli 2001 - 20:08 #11
hov.
linierne :
sprintf(buffer,\"0.14%f\",bel);
bel = atof(double);
skal ændres - tyrkfejl:
sprintf(buffer,\"%0.14f\",bel);
bel = atof(bel);

/denne her tekst bokst er vist ikke den bedste editor.
/haff ;-)

ps. erklærer lige selv h = 0.0.
Så skulle der vist ikke være flere fejl.
Avatar billede madsen666 Nybegynder
23. juli 2001 - 12:04 #12
Tak halt!

Godt svar.... Hvorfor tænkte jeg ikke på det... :)
Avatar billede madsen666 Nybegynder
23. juli 2001 - 12:05 #13
ups.... sæt lige halt=haff :)
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
Kurser inden for grundlæggende programmering

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