View Full Version : [C] XOR bitwise su double
Salve,
conoscete un modo per usare l'operatore '^', per lo XOR bitwise, su due double?
Gli operatori bitwise in C possono essere utlizzati solo con interi, non c'è un modo che permette di riversare i double in un long int o long long int e operare lo XOR?
Grazie. A presto.
BrutPitt
14-04-2009, 20:12
Non so a cosa ti serva... ma utilizzando cast e puntatori... puoi usare gli operatori bitwise su locazioni di double... attraverso i valori dei puntatori "long long"
Una cosa del genere:
double a, b, result;
long long *aInt = (long long *)&a;
long long *bInt = (long long *)&b;
long long *rInt = (long long *)&result;
a=1.0; b=2.33;
*rInt=*aInt^*bInt;
printf("%lx, %lx, %lx, %f, %f, %f\n", *aInt, *bInt, *rInt, a, b, result);
Non so a cosa ti serva... ma utilizzando cast e puntatori... puoi usare gli operatori bitwise su locazioni di double... attraverso i valori dei puntatori "long long"
Una cosa del genere:
double a, b, result;
long long *aInt = (long long *)&a;
long long *bInt = (long long *)&b;
long long *rInt = (long long *)&result;
a=1.0; b=2.33;
*rInt=*aInt^*bInt;
printf("%lx, %lx, %lx, %f, %f, %f\n", *aInt, *bInt, *rInt, a, b, result);
Ciao, devo realizzare un strategia di checkpoint tipo raid 1. Tutti i processori inviano lo xor bitwise dei dati ad un processore.
Se un processore cade posso recuperare i dati effettuano sempre lo xor logico dei dati restanti con quelli salvati.
Così
check = a ^ b;
Se perdo il valore di a lo recupero così
a = check ^ b;
La tua soluzione non funziona. Dopo le operazioni ottengo solo tutti zero.
Grazie lo stesso, a presto.
BrutPitt
15-04-2009, 10:14
Certo che, conditio sine qua non affinche' funzioni e' che:
sizeof(long long) == sizeof(double)
Altrimenti e' necessario creare una union di tipo adeguato a contenere un double.
Nell'esempio c'e' sia il metodo di ieri che la union... che puoi modificarti a seconda dell'esigenza... e funzionano entrambi:
#include <stdio.h>
#include <stdlib.h>
typedef union _CNV {
double d;
long long l;
unsigned char c[8];
} CNV;
int main(void)
{
double a, b, result;
long long *aInt = (long long *)&a;
long long *bInt = (long long *)&b;
CNV au, bu;
a=1.44; b=2.33;
au.d=1.44; bu.d=2.33;
printf("sizeof longlong %d, sizeof double %d\n\n", sizeof(long long), sizeof(double));
printf("Stampa variabili:\n");
printf("aInt=%lx, bInt=%lx\na=%f, b=%f\naViaInt=%f bViaInt=%f\n", *aInt, *bInt, a, b, *((double *)aInt), *((double *)bInt));
printf("Stampa Union:\n");
printf("aInt=%lx, bInt=%lx\na=%f, b=%f\naViaC[8]=%f bViaC[8]=%f\n\n", au.l, bu.l, au.d, bu.d, *((double *)au.c), *((double *)bu.c));
printf("ruoto i valori double via xor i valori:\n\n");
*aInt^=*bInt;
*bInt^=*aInt;
*aInt^=*bInt;
au.l^=bu.l;
bu.l^=au.l;
au.l^=bu.l;
printf("Stampa variabili ruotate:\n");
printf("aInt=%lx, bInt=%lx\na=%f, b=%f\naViaInt=%f, bViaInt=%f\n", *aInt, *bInt, a, b, *((double *)aInt), *((double *)bInt));
printf("Stampa Union ruotata:\n");
printf("aInt=%lx, bInt=%lx\na=%f, b=%f\naViaC[8]=%f bViaC[8]=%f\n\n", au.l, bu.l, au.d, bu.d, *((double *)au.c), *((double *)bu.c));
}
e questo e' l'output che ottengo:
sizeof longlong 8, sizeof double 8
Stampa variabili:
aInt=3ff70a3d70a3d70a, bInt=4002a3d70a3d70a4
a=1.440000, b=2.330000
aViaInt=1.440000 bViaInt=2.330000
Stampa Union:
aInt=3ff70a3d70a3d70a, bInt=4002a3d70a3d70a4
a=1.440000, b=2.330000
aViaC[8]=1.440000 bViaC[8]=2.330000
ruoto i valori double via xor i valori:
Stampa variabili ruotate:
aInt=4002a3d70a3d70a4, bInt=3ff70a3d70a3d70a
a=2.330000, b=1.440000
aViaInt=2.330000, bViaInt=1.440000
Stampa Union ruotata:
aInt=4002a3d70a3d70a4, bInt=3ff70a3d70a3d70a
a=2.330000, b=1.440000
aViaC[8]=2.330000 bViaC[8]=1.440000
P.S.
Nota che stampo i valori double anche col c[8] della union, forzando un cast... nella ultima printf
cdimauro
15-04-2009, 10:25
Salve,
conoscete un modo per usare l'operatore '^', per lo XOR bitwise, su due double?
Gli operatori bitwise in C possono essere utlizzati solo con interi, non c'è un modo che permette di riversare i double in un long int o long long int e operare lo XOR?
Grazie. A presto.
E' una soluzione assolutamente da evitare, in quanto legata alla particolare architettura e/o compilatore.
Poi non capisco che senso abbia eseguire lo xor di due double. Qual è il tuo vero scopo?
BrutPitt
15-04-2009, 12:21
E' una soluzione assolutamente da evitare, in quanto legata alla particolare architettura e/o compilatore.
Poi non capisco che senso abbia eseguire lo xor di due double. Qual è il tuo vero scopo?
Il motivo l'aveva spiegato: una tipologia tipo raid1.
del dato condiviso si salva lo XOR:
check = a ^ b;
Se "muore" a lo si recupera via:
a = check ^ b;
Se "muore" b si recupera via:
b = a ^ check;
Insomma una ridondanza del solo 50% su un'eventuale ripristino dati.
Be', l'esempio precedente... con un po' di criterio... lo si puo' fare assolutamente portabile, anche ingorando il tipo di architettura, quanto sia grande un duoble e facendo finta anche che un char non sia per forza un byte:
#include <stdio.h>
#include <stdlib.h>
typedef union _CNV {
double d;
char c[sizeof(double)/sizeof(char)];
} CNV;
int main(void)
{
CNV au, bu;
int i;
au.d=1.44; bu.d=2.33;
printf("a=%f, b=%f\n\n",au.d, bu.d);
for(i=0;i<sizeof(double);i+=sizeof(char)) {
au.c[i]^=bu.c[i];
bu.c[i]^=au.c[i];
au.c[i]^=bu.c[i];
}
printf("Stampa Union ruotata:\n");
printf("a=%f, b=%f\n\n",au.d, bu.d);
}
Poi voleva essere uno spunto, in cui prospettavo diverse sfaccettature (anche l'uso dei char)... e sta a lui scegliere se prediligere la portabilita' o la velocita' di calcolo.
Sicuramente non voleva essere la soluzione "assoluta" o "confezionata" al suo problema... ;)
cdimauro
15-04-2009, 15:31
Capito. Rimane comunque valido all'interno della medesima architettura / compilatore.
Vi ringrazio per le risposte.
Io cerco una soluzione che sia portabile. L'ultima soluzione lo è?
cdimauro
16-04-2009, 20:26
No. Qualunque assunzione fai sulla struttura di un double la rende non portabile.
Se, però, rimani all'interno della stessa piattaforma, non ci sono problemi.
BrutPitt
16-04-2009, 22:33
No. Qualunque assunzione fai sulla struttura di un double la rende non portabile.
Se, però, rimani all'interno della stessa piattaforma, non ci sono problemi.
Permettimi di dissentire.
Con la definizione:
typedef union _CNV {
double d;
char c[sizeof(double)/sizeof(char)];
} CNV;
Viene mappato un array di caratteri della dimensione di un double esattamente nell'area di memoria del double... e la dimensione non e' predefinita, ma viene restituita all'atto della compilazione proprio dal compilatore della specifica piattaforma/architettura, grazie all'uso del sizeof... anche nell'inverosimile caso in cui il double non segua lo standard IEEE.
E sempre grazie al "sizeof" ogni byte dell'array, e quindi del double, viene elaborato, anche nel caso "strano" in cui un char fosse di 2 o 4 byte:
for(i=0;i<sizeof(double);i+=sizeof(char)) {
au.c[i]^=bu.c[i];
bu.c[i]^=au.c[i];
au.c[i]^=bu.c[i];
}
L'ultimo codice che ho postato e' portabile:
basta un qualsiasi compilatore ANSI-C... anzi per le istruzioni che sono presenti basterebbe anche che sia solo conforme allo standard "K&R".
Ed e' utilizzabile dai microcontrollori 8/16bit fino alle attuali architetture a 64bit... indipendente dal sistema operativo... sia su processori big-endian che su processori little-endian.
cdimauro
17-04-2009, 07:11
Che funzioni sulla STESSA piattaforma l'avevo già detto io.
Ma prova a salvare quei dati e a portarli in un'ALTRA piattaforma, e poi dimmi se ti funziona sempre tutto...
Che funzioni sulla STESSA piattaforma l'avevo già detto io.
Ma prova a salvare quei dati e a portarli in un'ALTRA piattaforma, e poi dimmi se ti funziona sempre tutto...
Ciao,
su questo penso che tu abbia ragione. I dati se salvati, ad esempio in binario, penso che possano essere utilizzati solo sull'architettura sulla quale sono sono stati creati.
Penso che tutte le soluzioni a questo problema siano soggette a questa limitazione, o sbaglio?
Grazie, a presto.
cdimauro
17-04-2009, 12:45
Sì, con soluzioni come quella proposta.
Il problema lo si risolve con apposito codice di marshalling o serializzazione che dir si voglia.
BrutPitt
17-04-2009, 14:56
Che funzioni sulla STESSA piattaforma l'avevo già detto io.
Ma prova a salvare quei dati e a portarli in un'ALTRA piattaforma, e poi dimmi se ti funziona sempre tutto...
Scusa, non avevo capito ti riferissi alla portabilita' del salvataggio/ripristino dati, anche perche' sinceramente qui era stato chiesto come fare lo XOR sui dati double.
Oltretutto avevo precisato che non era mia intenzione dare una soluzione "assoluta" o "confezionata" al suo sistema raid1, ma solo di come fare uno XOR, portabile, sui double... e in tal modo avevo inteso e risposto.
Cosa farne dello XOR ottenuto era inteso che doveva essere sua cura, in base alle esigenze che aveva... tant'e' che nell'esempio operavo una semplice rotazione.
Per cui, quando ho letto la tua risposta, non pensavo ti riferissi ai dati da salvare/ripristinare :)
Ciao,
su questo penso che tu abbia ragione. I dati se salvati, ad esempio in binario, penso che possano essere utilizzati solo sull'architettura sulla quale sono sono stati creati.
Penso che tutte le soluzioni a questo problema siano soggette a questa limitazione, o sbaglio?
Grazie, a presto.
Se entriamo nel merito salvataggio/ripristino dati, per quanto inverosimile, piu' che dei float e dei double (che seguono uno standard di dimensione e rappresentazione binaria, praticamente ovunque) piuttosto mi preoccuperei degli altri tipi di dati: int, long, long long, etc..
Quelli si' sono architettura/S.O. dipendenti anche nelle dimensioni, ma che qui non hai mensionato.
I double, in definitiva, appartengono allo standard ANSI/IEEE 754 ed e' uno standard praticamente su tutte le architetture/S.O. che definiscono una "doppia precisione in virgola mobile", in hardware o in emulazione.
Ed il ripristino si ridurrebbe ad un ciclo inverso di XOR nel caso in cui l'architettura che subentra differisca nel byte-order (big-endian/little-endian)
Piu' complesso e' il ripristino di int, long, long long, etc. nel caso in cui differiscano anche per dimensione.
E i bit di stato, indirizzi e quant'altro?
Ma stiamo parlando di ripristino di interi processi, di ripristino di un cluster di calcolo distribuito... o di cosa?
Scusa, non avevo capito ti riferissi alla portabilita' del salvataggio/ripristino dati, anche perche' sinceramente qui era stato chiesto come fare lo XOR sui dati double.
Oltretutto avevo precisato che non era mia intenzione dare una soluzione "assoluta" o "confezionata" al suo sistema raid1, ma solo di come fare uno XOR, portabile, sui double... e in tal modo avevo inteso e risposto.
Cosa farne dello XOR ottenuto era inteso che doveva essere sua cura, in base alle esigenze che aveva... tant'e' che nell'esempio operavo una semplice rotazione.
Per cui, quando ho letto la tua risposta, non pensavo ti riferissi ai dati da salvare/ripristinare :)
Se entriamo nel merito salvataggio/ripristino dati, per quanto inverosimile, piu' che dei float e dei double (che seguono uno standard di dimensione e rappresentazione binaria, praticamente ovunque) piuttosto mi preoccuperei degli altri tipi di dati: int, long, long long, etc..
Quelli si' sono architettura/S.O. dipendenti anche nelle dimensioni, ma che qui non hai mensionato.
I double, in definitiva, appartengono allo standard ANSI/IEEE 754 ed e' uno standard praticamente su tutte le architetture/S.O. che definiscono una "doppia precisione in virgola mobile", in hardware o in emulazione.
Ed il ripristino si ridurrebbe ad un ciclo inverso di XOR nel caso in cui l'architettura che subentra differisca nel byte-order (big-endian/little-endian)
Piu' complesso e' il ripristino di int, long, long long, etc. nel caso in cui differiscano anche per dimensione.
E i bit di stato, indirizzi e quant'altro?
Ma stiamo parlando di ripristino di interi processi, di ripristino di un cluster di calcolo distribuito... o di cosa?
Devo realizzare un meccanismo di checkpointing con MPI, in ambiente di calcolo parallelo. I dati da salvare sono vettori double, che vengono inviati ad un processore con una Reduce, tale processori devo salvare lo XOR dei dati.
In pratica, salvo tutti dati su file binari, poi per recuperare i dati leggo i file e faccio la decodifica.
BrutPitt
17-04-2009, 17:26
MPI... ma non lo potevi dire subito? :D
In MPI il trasferimento dati tra i cluster viene fatto in modo assolutamente non ambiguo, ed ogni differenza cosi' come l'architettura big/little endian e/o la lunghezza dati e' assolutamente trasparente ai cluster.
Pero' ha tipi di dati interni, e devi usare quelli.
Nell'esempio precedente... dovresti sostituire "double" con MPI_DOUBLE, e "char" con MPI_CHAR.
Mi verrebbe quasi da dire che ho fatto bene a non preoccuparmi di dove finissero i dati... se non fosse che anche l'esempio di XOR e' inutile... :D
Se non ricordo male MPI_reduce non opera direttamente lo XOR bitwise, anche su MPI_FLOAT e MPI_DUOBLE?
MPI... ma non lo potevi dire subito? :D
In MPI il trasferimento dati tra i cluster viene fatto in modo assolutamente non ambiguo, ed ogni differenza cosi' come l'architettura big/little endian e/o la lunghezza dati e' assolutamente trasparente ai cluster.
Pero' ha tipi di dati interni, e devi usare quelli.
Nell'esempio precedente... dovresti sostituire "double" con MPI_DOUBLE, e "char" con MPI_CHAR.
Mi verrebbe quasi da dire che ho fatto bene a non preoccuparmi di dove finissero i dati... se non fosse che anche l'esempio di XOR e' inutile... :D
Se non ricordo male MPI_reduce non opera direttamente lo XOR bitwise, anche su MPI_FLOAT e MPI_DUOBLE?
Ciao, ho usato già i dati predefiniti di MPI. Ho provato ad implementare la tua soluzione ma in fase di recupero i dati non vengono letti correttamente. Forse ci sono degli errori, dopo controllo con cura.
MPI effettua lo xor solo su char :D .
Grazie, a presto.
Ad esempio il seguente codice non funziona:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
typedef union _CNV {
double d;
char c[sizeof(double)/sizeof(MPI_CHAR)];
} CNV;
void xorDouble( double *, double *, int *, MPI_Datatype * );
int main( int argc, char **argv )
{
int id, size, i, n;
MPI_Op MPI_DOUBLE_XOR;
double *send, *receive , *rec, *send2;
char file[250];
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &id );
MPI_Comm_size( MPI_COMM_WORLD, &size );
n = atoi(argv[1]);
send = (double *)calloc(n,sizeof(double));
send2 = (double *)calloc(n,sizeof(double));
receive = (double *)calloc(n,sizeof(double));
rec = (double *)calloc(n,sizeof(double));
// INIZIALIZZO I VETTORI
if ( id == 0) {
for (i=0; i < n; i++)
send[i] = i;
}
else {
for (i=0; i < n; i++)
send[i] = 1.0 + i;
}
MPI_Op_create( (MPI_User_function *)xorDouble, 1, &MPI_DOUBLE_XOR );
MPI_Reduce(send,receive,n,MPI_DOUBLE,MPI_DOUBLE_XOR,0,MPI_COMM_WORLD);
if (id == 0) send2 = receive;
else send2 = send;
/* ADESSO FACCIO L'XOR TRA IL RISULTATO DEL VECCHIO REDUCE E IL DATO
DI ORIGINE DEL PROC. 1, DOVREI AVERE IL DATO INIZIALE DEL PROC 0 */
MPI_Reduce(send2,rec,n,MPI_DOUBLE,MPI_DOUBLE_XOR,0,MPI_COMM_WORLD);
if ( id == 0) {
for (i=0; i < n; i++)
printf("%f\n", rec[i]);
}
MPI_Finalize();
return 0;
}
Nel caso di un array di dimensione 3, ho il seguente risultato:
1.000000
inf
1.500000
A presto.
DanieleC88
18-04-2009, 22:02
Che funzioni sulla STESSA piattaforma l'avevo già detto io.
Ma prova a salvare quei dati e a portarli in un'ALTRA piattaforma, e poi dimmi se ti funziona sempre tutto...
Non è nemmeno detto che diversi compilatori riservino uguale spazio per un double (ho notato differenza tra MSVC e GCC ad esempio). :(
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.