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