Gå til innhold

Anbefalte innlegg

Hvis en har et tall, for eksempel:

double x = 123,4567;

 

Så kan en finne det før komma, ved å

double/int y = (int) x;

 

For å finne det etter komma, kan man

double z = x - (int) x;

 

Er disse operasjonene trygge med tanke på flyttall osv? Tenker da spesielt på den siste. Kan det bli rot, eller er disse to operasjonene helt trygge?

 

Er det dessuten noen viktig forskjell på de to uttrykkene nedenunder? nøyaktighet, hastighet, etc.

int y = (int) x;
int y = Math.Floor(x);

Lenke til kommentar
Videoannonse
Annonse

Ok, nå sjekket jeg med disassembly

 

double en_verdi = Math.PI;
double dbl_val = Math.Floor(en_verdi);
double int_val = (int)en_verdi;

 

Ble til dette

 

			double en_verdi = Math.PI;
00000034  fld		 qword ptr ds:[00CB11B0h] 
0000003a  fstp		qword ptr [ebp-44h] 
		double dbl_val = Math.Floor(en_verdi);
0000003d  fld		 qword ptr [ebp-44h] 
00000040  sub		 esp,8 
00000043  fstp		qword ptr [esp] 
00000046  call		792D3B29 
0000004b  fstp		qword ptr [ebp-5Ch] 
0000004e  fld		 qword ptr [ebp-5Ch] 
00000051  fstp		qword ptr [ebp-4Ch] 
		double int_val = (int)en_verdi;
00000054  movsd	   xmm0,mmword ptr [ebp-44h] 
00000059  cvttsd2si   eax,xmm0 
0000005d  mov		 dword ptr [ebp-60h],eax 
00000060  fild		dword ptr [ebp-60h] 
00000063  fstp		qword ptr [ebp-54h]

 

Wow! jeg er imponert! .NET bruker MMX!

 

Utifra dette ser det ut til at det er mer effektivt å caste.

Lenke til kommentar
Om det er noen forskjell på Math.Floor og cast til int vet jeg ikke, jeg holder en knapp på 'neppe'

floor(-2.6) = -3

(int)-2.6 = -2

 

Det ser overraskende mer effektivt ut, ja. Jeg kan ikke skjønne hvorfor de har gjort .Floor() så mye mer omfattende?

Vel, det eneste du ser fra den asm-koden er jo funksjonkalloverheadet, du kan jo ikke se om floor faktisk er mye mer omfattende. Floor er avrunding nedover, casting er trunkering. Men floor er en matematisk definert funksjon som må implementeres deretter ved å ta hensyn til positive og negative verdier, men det kan dog godt hende at det fins en asm-instruksjon for det også, men det kan du ikke se fra koden. En cast mellom to typer er derimot ikke det, og (ihvertfall i C) er det heller ikke definert hvordan en cast fra double/float til int det skal implementeres, den kan f.eks implementeres som floor eller ceiling eller noe helt annet. Men det er vanligst med optimaliserte assemblyinstruksjoner for en slik cast (cvttsd2si eax,xmm0 i GeirGrusom sitt eksempel, som betyr "Convert scalar double-precision floating-point value (with truncation) to signed doubleword of quadword integer (SSE2)").

 

Og en annnen ting man også må huske på, som gjelder både floor og cast, er at flyttall har avrundingsfeil, så det kan hende du vil slenge på litt epsiloner her og der omtrent som man gjør når man sammenligner to flyttall.

Endret av teflonpanne
Lenke til kommentar
..., så det kan hende du vil slenge på litt epsiloner her og der omtrent som man gjør når man sammenligner to flyttall.

Say whaat? :hmm:

 

uansett, dette var jo egentlig litt imponerende :p hva folk kan finne ut av.... hehe.

Vet du hvordan du tester om to flyttall er like?

Hvis du har et flyttall som du kjører gjennom en løkke og inkrementerer med 0.1 for hver gang f.eks og vil teste om det blir 3.14 f.eks, så er det nemlig ikke bare å gjøre if (f == 3.14) som det er med integerer siden flyttall ikke er nøyaktig representert i minnet (se her hvordan ieee-flyttall er implementert med mantissa og eksponent). Du får avrundingsfeil så det er ikke sikkert at f noen gang vil bli akkurat 3.14 men 3.139 eller 3.141 osv, og da vil testen aldri bli true. Så den vanligste metoden er å definere en float epsilon = 0.0001 f.eks og så gjøre if (fabs(3.14 - f) < epsilon) som betyr hvis f ligger 0.0001 innenfor verdien av 3.14 så sier vi at den er lik. Noe av det samme må du da gjøre med floor. Tenk f.eks på floor(0.6/0.2), i C blir dette 2, men 0.6/0.2 er jo 3, men pga flyttall ikke blir representert nøyaktig så blir 0.6/0.2 2.99999etellerannet, så floor(2.999999) = 2. Da kan du f.eks gjøre floor((0.6/0.2) + epsilon) og så blir svaret 3 :)

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...