/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
fmod og division
Fra : Rolf Kristensen


Dato : 30-01-03 20:34

Jeg har brug for at vide om en double divideret med en anden double giver et
heltal.
Jeg tænkte derfor straks at det var nok lige noget for en modulus.

double test = 0.0;
test = fmod(621658.09/0.01, 1); // Fejler test != 0
test = fmod(621658.09*100, 1); // Ok test == 0
test = fmod(62165809, 1); // Ok test == 0

Hvorfor fejler den første ? sker der noget specielt i den division ?
Jeg har prøvet med andre divisioner og de virker fint.

-Rolf

P.S. Kun testet på MS Dev 5.0

HP : http://snakefoot.tk/



 
 
Thomas Lykkeberg (30-01-2003)
Kommentar
Fra : Thomas Lykkeberg


Dato : 30-01-03 21:47

On Thu, 30 Jan 2003 20:33:43 +0100, "Rolf Kristensen"
<sweaty1@hotmail.com> wrote:

>Jeg har brug for at vide om en double divideret med en anden double giver et
>heltal.
>Jeg tænkte derfor straks at det var nok lige noget for en modulus.
>
> double test = 0.0;
> test = fmod(621658.09/0.01, 1); // Fejler test != 0
> test = fmod(621658.09*100, 1); // Ok test == 0
> test = fmod(62165809, 1); // Ok test == 0
>
>Hvorfor fejler den første ? sker der noget specielt i den division ?
>Jeg har prøvet med andre divisioner og de virker fint.
>
>-Rolf
>
Hej Rolf. Det er en af computerverdenens små spidsfindigheder. Prøv en
gang at tildele en double værdien 621658.09/0.01. Her vil du nok
hurtigt se at denne værdi ikke svarer til det du regner med. Det
skyldes i brund og grund at det nok er floating point, men med en
endelig præcision.

Af floating point representationer i en "fixed-point" verden findes
der følgende gengse typer (IEEE standarder):

Signle precision (32 bit)
Souble precision (64 bit)

Generelt for et floating-point tal gælder at det udtrykkes som en
"sign-bit" en "exponent" og en "fractional" del. For 32 bit precision
f.eks.

1 bit til fortegn (S)
8 bit til eksponent (E)
23 bit til "brøken", eller den fraktionelle del. (F)

Tallet som disse bit så udtrykker ud regnes som følger:

(-1)^S * 2^(E-127) * (1 + (F/2^23))

Skal tallet 23.889276 f.eks omregnes til floating point representation
vil det først skulle "normaliseres". Dette gøres ved at finde den
største exponent af 2 tallet kan udtrykkes ved.

INT( LOG10(23.889276) / LOG10(2) ) = 4

Dette giver så E = (4+127) = 131. S kan hurtigt bestemmes da fortegnet
jo er (+), så S = 0. F bestemmes så ud fra:

F = INT(((23.889276 / 2^4) - 1) * 2^23) = 4136252

Representeret binært i et 32 bit register:
0 10000011 01111110001110100111100
S E F

Voila..

Regner vi nu den "anden vej".....

(-1)^0 * 2^(131-127) * (1 + (4136252/2^23)) = 23.8892745971

Dette viser jo tydeligt en fejl på 0.0000012029

Husk på i denne situation at dit program vil opdatte tallet med den
"fejl margin". En løsning ville selvfølgelig være at øge til Double
precision (eller noget højere 80/96 bit halløj), men problemet vil
altid være der i størrer eller mindre grad.

Prøv evt. for sjov at at evaluerer din egen compilers precision ved at
"snuse" på det floating point tal, som compileren kommer frem til.

<CODE>
float tal = 23.889276;
unsigned long *ptr;

ptr = (unsigned long *)&tal;
printf("%X",*ptr);
</CODE>

Mvh
Thomas


Rolf Kristensen (31-01-2003)
Kommentar
Fra : Rolf Kristensen


Dato : 31-01-03 00:48

"Thomas Lykkeberg" <Fornavn.Efternavn@privat.dk> wrote in message
news:ul1j3voj030msg3bmgf5uv7c4uf5hpqais@4ax.com...
> On Thu, 30 Jan 2003 20:33:43 +0100, "Rolf Kristensen"
> <sweaty1@hotmail.com> wrote:
>
> Husk på i denne situation at dit program vil opdatte tallet med den
> "fejl margin". En løsning ville selvfølgelig være at øge til Double
> precision (eller noget højere 80/96 bit halløj), men problemet vil
> altid være der i størrer eller mindre grad.

Hej Thomas, Tak for den meget uddybede forklaring . Jeg regnede
faktisk med at doublen kunne klare sådan en præcision uden at gå i
stykker. Det er jo ikke verden største tal den regner på.

> Prøv en gang at tildele en double værdien 621658.09/0.01

Dette resultat fik jeg i MS Dev 5.0 debugger

double test = 621658.09/0.01; // 62165809.000000
test = 62165809 - test; // 7.4505805969238e-009

Forsøgte også at bruge long double (MS Dev 80 bit) og den fejler
også i det overstående eksempel.
Tror jeg har forstået at double/float ikke er helt præcis, men er man
helt fortabt hvis man ønsker at regne med decimaler ? For lige meget
hvormeget præcision så vil det jo altid kun være lige ved eller næsten :

http://members.lycos.co.uk/keithmbriggs/doubledouble.html
http://www.nersc.gov/~dhbailey/mpdist/mpdist.html
http://www.cs.berkeley.edu/~yozo/
http://aksenov.freeshell.org/lerchphi.html (Lerch's Transcendent)

Eller skal man holde helt op med at bruge double og satse på kæmpe
int's og håbe de ikke laver overløb ? (men det bliver vist lidt sløvt)

http://www.rossi.com/sqr2.htm (bigInt)

-Rolf



Mogens Hansen (31-01-2003)
Kommentar
Fra : Mogens Hansen


Dato : 31-01-03 06:34


"Rolf Kristensen" <sweaty1@hotmail.com> wrote in message
news:SOi_9.48805$Hl6.6180930@news010.worldonline.dk...

[8<8<8<]
> Forsøgte også at bruge long double (MS Dev 80 bit) og den fejler
> også i det overstående eksempel.

Er du sikker på at "long double" er 80 bit ?
På et tidspunkt (jeg husker ikke præcist hvornår) skiftede Microsoft "long
double" fra at være 80 bit til at være 64 bit (lige som double).
Det var så vidt jeg husker af hensyn til compatibilitet med Alpha
processoren.

Med såvel Microsoft Visual C++ V6.0 og Microsoft Visual C++ .NET skriver
følgende program

<code>
#include <iostream>

int main()
{
using namespace std;
cout << "double: " << sizeof(double) << endl;
cout << "long double: " << sizeof(long double) << endl;
}
</code>

<output>
double: 8
long double: 8
</output>

Venlig hilsen

Mogens Hansen



Rolf Kristensen (31-01-2003)
Kommentar
Fra : Rolf Kristensen


Dato : 31-01-03 07:33

"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:b1d1o9$1b3c$1@news.cybercity.dk...
>
> "Rolf Kristensen" <sweaty1@hotmail.com> wrote in message
> news:SOi_9.48805$Hl6.6180930@news010.worldonline.dk...
>
> [8<8<8<]
> > Forsøgte også at bruge long double (MS Dev 80 bit) og den fejler
> > også i det overstående eksempel.
>
> Er du sikker på at "long double" er 80 bit ?

Næh men jeg søgte efter "long double" i MS Dev5's hjælp og følgende stump
information dukkede op (Skal ikke afgøre at det er gammel dokumentation som
de har glemt at fjerne i hjælpen) :

Microsoft Specific ®

The long double contains 80 bits: 1 for sign, 15 for exponent, and 64 for
mantissa. Its range is +/-1.2E4932 with at least 19 digits of precision.
Although long double and double are separate types, the representation of
long double and double is identical.

END Microsoft Specific






Richard Flamsholt (31-01-2003)
Kommentar
Fra : Richard Flamsholt


Dato : 31-01-03 20:47

"Rolf Kristensen" <sweaty1@hotmail.com> skrev:
>Eller skal man holde helt op med at bruge double og satse på kæmpe
>int's og håbe de ikke laver overløb ? (men det bliver vist lidt sløvt)

Måske er der andre løsninger end double, ja. Det kommer an på problemet.

Fx kan et økonomiprogram med fordel regne i hele ører fremfor kroner,øre
fordi det så netop slipper for afrundingsfejl. Måske har dit problem en
tilsvarende løsning, der på enkel vis sikrer 100% præcision.

--
Richard Flamsholt
richard@flamsholt.dk - www.richard.flamsholt.dk

Søg
Reklame
Statistik
Spørgsmål : 177491
Tips : 31966
Nyheder : 719565
Indlæg : 6408458
Brugere : 218886

Månedens bedste
Årets bedste
Sidste års bedste