Codificați mai multe intrări într-un dublu

Aș dori să codific o pereche de inci într-un dublu. De exemplu, spun că am vrut să trec o funcție:

foo(int a, int b)

dar în schimb vreau doar un dublu pentru a reprezenta cele două inci (adică):

foo(double aAndB)

În prezent o fac prin a avea un int pe fiecare parte a zecimalei (adică 10 și 15 ar deveni 10.15) și apoi convertirea la un stringstream tokenising și extragerea celor două numere.

Cu toate acestea, acest lucru are un defect evident atunci când vine vorba de numere de 10 și 10 adică devine 10.1.

Există o modalitate de a face acest lucru printr-o metodă matematică dificilă, astfel încât să pot trece o funcție dublă care reprezintă 2 inți?

Mulțumiri.

0
@Ben: nu este interesant. Este doar o problemă a numărului de biți și a unei manipulări a unui pointer. Sau folosiți o uniune. Este pur și simplu un design rău dacă trebuie să faceți asta.
adăugat autor Tobias Langner, sursa
Ce încerci să faci cu asta? Deoarece ai întrebarea etichetat cu encoding , presupun că într-un anumit punct doriți să decodificați dublul pentru a obține cele două inci înapoi. În acest caz, doriți ca codarea să nu fie pierdută?
adăugat autor Vikas, sursa
Ce este în neregulă cu 10.1 ? Vreau să spun că dacă ați fi scris, nu ați scrie 10.10 dacă cineva ți-a spus să scrii 10 și o sută ...
adăugat autor RedX, sursa
Apoi întrebarea este cum se face diferențierea între int (10) .int (1) și int (10) .int (10) .int (100) și int (10) .int (001) ? Un alt mod de a întreba este: Care este numărul minim de locuri zecimale?
adăugat autor RedX, sursa
@Vikas Da la ambele
adăugat autor Fantastic Mr Fox, sursa
Mă gândeam să încerc să o fac prin codificarea insulelor în binarul dublului
adăugat autor Fantastic Mr Fox, sursa
@RedX Dar ceea ce vreau IDS pentru funcția mea să fie capabil să ia un dublu și împărțit-o înapoi la original 2 inti. Dacă am obține 1 în loc de 10, atunci programul obiceiul de lucru.
adăugat autor Fantastic Mr Fox, sursa
@ Paolo 1. este o întrebare interesantă. 2. pentru că am un tip abstracted cu o metodă din fabrică care ia doar dubluri și trebuie să trec 2 inci
adăugat autor Fantastic Mr Fox, sursa
@TobiasLangner Aceasta este opinia ta, eu incerc pur si simplu ceva de interes pentru a vedea daca se poate face. De ce atât de multă negativitate?
adăugat autor Fantastic Mr Fox, sursa
Pentru toți cei care au încercat să domine această metodă, eu deja implementez acest alt mod, am vrut doar să văd dacă acest lucru a fost posibil. Încercați să nu faceți totul așa de repede. Ca o notă suplimentară, vă mulțumesc tuturor celor care au răspuns bine.
adăugat autor Fantastic Mr Fox, sursa
Nu puteți trece nici măcar 0 și 1 aici deoarece 0.1 nu este exact reprezentabilă.
adăugat autor David Heffernan, sursa
Și de ce ai face asta?
adăugat autor Paolo Brandoli, sursa

6 răspunsuri

Deoarece (de obicei) un dublu are 64 de biți în el și fiecare int are 32 de biți, credeți că ați putea să stocați doar biții în dublu direct, de ex .:

int32_t i1 = rand();
int32_t i2 = rand();
int64_t x = (((int64_t)i1)<<32) | ((int64_t)i2);
double theDouble;
memcpy(&theDouble, &x, sizeof(theDouble));

... și a face acest lucru "aproape de lucrări". Asta este, funcționează bine pentru multe valori posibile ale i1 și i2 - dar nu pentru toate. În special, pentru formatul în virgulă mobilă IEEE754, toate valorile în care biții exponenți sunt setați la 0x7ff vor fi tratați ca indicând "NaN", iar hardware-ul cu punct de plutire poate (și face) să transforme șabloanele de biți echivalente NaN înapoi la preferințele Modelul bitului NaN atunci când treceți un dublu ca argument, etc.

Din această cauză, umplerea a două numere de 32 de biți într-un dublu va apărea în majoritatea cazurilor, dar dacă îl testați cu toate valorile posibile de intrare, veți găsi câteva cazuri în care valorile au suferit modificări neașteptate în timpul șederii în interiorul dublei și au ieșit ca valori diferite când le-ați decodat din nou.

Bineinteles, ai putea obtine acest lucru prin a fi atent doar pentru a seta biti mantisa de dublu, dar care va va da doar 26 de biți pe intreg, astfel încât veți putea să stocați numai valori întregi de +/- 33.554.432 sau cam asa ceva. Poate că e în regulă, în funcție de cazul dvs. de utilizare.

Sfatul meu este să găsești un mod diferit de a face tot ce vrei să faci. Stocarea datelor non-flotante într-o variabilă în virgulă mobilă solicită probleme, mai ales dacă doriți ca codul dvs. să fie în totalitate portabil.

5
adăugat

Dacă sunteți norocoși și un int este o jumătate de dublu, puteți stoca acele inci ca acesta:

int a = 10;
int b = 20;
double d;

*(int *)&d = a;
*((int *)&d + 1) = b;

int outa = *((int *)&d);
int outb = *(((int *)&d) + 1);
printf("%d %d\n", outa, outb);

Acest lucru nu funcționează în general/portabilitate. Dacă un dublu și int au același număr de biți ceea ce vrei este imposibil.

4
adăugat
acest lucru va funcționa pe 32 de biți - cel mai probabil. Dar ca user85509 nu este portabil. Dar chiar dacă vă restrângeți la tipurile de 32 de biți întregi (există unele antete care le au) - este un semn pentru un design rău dacă aveți nevoie să faceți acest lucru.
adăugat autor Tobias Langner, sursa

A double can exactly represent an integer up to 53 bits. If you want to hold a 26-bit and a 27-bit integer, it's very easy: double combined = bits27*67108864.0 + bits26;

Rețineți că 67108864 este 2 ^ 26.

3
adăugat

Încercați să definiți o uniune ca aceasta:

struct two_int {
    int a;
    int b;
};

union encoding {
    struct two_int a;
    double c;
};

Dar a face acest lucru poate introduce problema cu portabilitatea. Verificați dublu, vă rugăm să uitați această abordare adecvată cazului dumneavoastră.

1
adăugat

Puteți face acest lucru folosind o mască binară și extrageți informații din "dublu".

De exemplu:

double encode(int a, int b)
{
    double d = 0;
    d = d | a; 
    d = d | (b << 8);
    return d;
}

double decode(double d)
{
    a = d & 0xFF;
    b = (d >> 8) & 0xFF;
}

În partea codificată, a va fi în cei 8 biți inferiori ai variabilei duble d, b va fi în cei 8 biți mai mari ai lui d.

1
adăugat

Dacă treceți întotdeauna două inci la acest parametru, atunci nu are sens să treci un dublu. În schimb, treceți fie cele două inci ca niște inci separate, fie le înfășurați într-un struct.

Modul în care faci acest lucru nu îți lasă nici o șansă să detectezi diferența dintre un dublu adevărat și doi inci. Și astfel am concluzionat că nu veți pierde nici o funcționalitate făcând ceea ce descriu mai sus.

0
adăugat
Dacă are control asupra interfeței din fabrică, ar trebui să facă acest lucru.
adăugat autor RedX, sursa
Acesta nu este un răspuns la întrebare. Mulțumesc pentru sfat, dar încerc doar așa ceva pentru moment.
adăugat autor Fantastic Mr Fox, sursa
De fapt, nici dvs., dacă citiți comentariul de sub întrebare, am pus în aplicare acest alt mod și am avut întotdeauna opțiunea. Tot ce am vrut să știu era dacă ar fi posibil. Scuzele mele, dar răspunsul tău nu este un răspuns la întrebare, ci doar un comentariu.
adăugat autor Fantastic Mr Fox, sursa
@Ben Este posibil să nu fie răspunsul pe care doriți să-l auziți, dar este probabil soluția problemei dvs.
adăugat autor David Heffernan, sursa