Convertire NSData alla variabile primitiva con IEEE-754 o complemento a due?
-
26-09-2019 - |
Domanda
Sono nuovo programmatore in Obj-C e cacao . Im un tentativo di scrivere un quadro che verrà utilizzata per leggere un file binari ( Flexible Image Transport Sistema o FITS i file binari, di solito utilizzati dagli astronomi). I dati binari, che mi interessa di estratto, possono avere vari formati e ottengo le sue proprietà leggendo l'intestazione delle FITS file.
Fino ad ora, riesco a creare una classe per memorizzare il contenuto della FITS file e di isolare l'intestazione in un oggetto NSString
ei dati binari in un oggetto NSData
. Riesco anche il metodo di scrittura che mi permetta di estrarre i valori chiave del colpo di testa che sono molto preziosi per interpretare i dati binari.
ora sto cercando di convertire l'oggetto NSData
in una matrice primitiva (array di double
, int
, short
...). Ma, qui, mi si blocca e gradirebbe qualsiasi aiuto.
In base alla documentazione ho circa FITS di file, ho 5 possibilità per interpretare i dati binari a seconda del valore della chiave BITPIX
:
BITPIX value | Data represented
8 | Char or unsigned binary int
16 | 16-bit two's complement binary integer
32 | 32-bit two's complement binary integer
64 | 64-bit two's complement binary integer
-32 | IEEE single precision floating-point
-64 | IEEE double precision floating-point
I già scrivere la pace di codice, mostrato di seguito, per cercare di convertire la NSData
in una matrice primitiva.
// self reefer to my FITS class which contain a NSString object
// with the content of the header and a NSData object with the binary data.
-(void*) GetArray
{
switch (BITPIX)
{
case 8:
return [self GetArrayOfUInt];
break;
case 16:
return [self GetArrayOfInt];
break;
case 32:
return [self GetArrayOfLongInt];
break;
case 64:
return [self GetArrayOfLongLong];
break;
case -32:
return [self GetArrayOfFloat];
break;
case -64:
return [self GetArrayOfDouble];
break;
default:
return NULL;
}
}
// then I show you the method to convert the NSData into a primitive array.
// I restrict my example to the case of 'double'. Code is similar for other methods
// just change double by 'unsigned int' (BITPIX 8), 'short' (BITPIX 16)
// 'int' (BITPIX 32) 'long lon' (BITPIX 64), 'float' (BITPIX -32).
-(double*) GetArrayOfDouble
{
int Nelements=[self NPIXEL]; // Metod to extract, from the header
// the number of element into the array
NSLog(@"TOTAL NUMBER OF ELEMENTS [%i]\n",Nelements);
//CREATE THE ARRAY
double (*array)[Nelements];
// Get the total number of bits in the binary data
int Nbit = abs(BITPIX)*GCOUNT*(PCOUNT + Nelements); // GCOUNT and PCOUNT are defined
// into the header
NSLog(@"TOTAL NUMBER OF BIT [%i]\n",Nbit);
int i=0;
//FILL THE ARRAY
double Value;
for(int bit=0; bit < Nbit; bit+=sizeof(double))
{
[Img getBytes:&Value range:NSMakeRange(bit,sizeof(double))];
NSLog(@"[%i]:(%u)%.8G\n",i,bit,Value);
(*array)[i]=Value;
i++;
}
return (*array);
}
Tuttavia, il valore stampo nel loop sono molto diversi dai valori attesi (rispetto utilizzando il software FITS ufficiali). Pertanto, ritengo che il Obj-C double
non utilizza il IEEE-754 di convenzione così come la Obj-C int
non sono < em> complemento a due . Sono veramente non hanno familiarità con questi due congressi ( IEEE e complemento a due ) e vorrei sapere come posso fare questa conversione con Obj-C .
in anticipo molte grazie per qualsiasi aiuto o informazioni.
Soluzione 4
Grazie mille. Il problema è stato veramente legato alla endian e non ero a conoscenza di questo. Onestamente, non sono mai stato veramente consapevoli del tipo di endian perché, fino ad ora, non sono mai stato confrontato al problema.
A proposito, ho trovato la soluzione, ringrazia tutti per le sue osservazioni. Perché può essere utile per altro sviluppatore, vi propongo una pace di codice che permette di convertire i NSData al primitivo, che cosa mai il tipo di endian. Questa è la soluzione che trovo (lavoro con la Fondazione e il quadro di cacao su OS X 10.5 e 10.6) e non può essere la migliore, quindi, l'uso a proprio rischio;)
// 1- CREATE AN ARRAY OF SIZE Nelements;
int Nelements = XXX;
double (*array)[Nelements];
// 2- Create the swapped double -> a double with the wrong bit order
NSSwappedDouble swappedValue;
// 3- The correct value
double Value;
// 4- Fill your array
int i=0, bit=0;
int BitStep=sizeof(double);
while(i<Nelements)
{
[MyNSData getBytes:&swappedValue range:NSMakeRange(bit,step)];
Value = NSSwapBigDoubleToHost(swappedValue); // or NSSwapLittleDoubleToHost depending of your endian type.
(*array)[i]=Value;
i++; bit+=BitStep;
}
Spero che questo può essere utile.
Altri suggerimenti
Objective-C utilizza IEEE-754 carri allegorici (come praticamente ogni sistema fa), così come interi in complemento a due. Credo che la vostra congettura è falsa. Forse si stanno avendo problemi di ordine?
Praticamente tutti i sistemi utilizzano complemento a due e IEEE 754, semplicemente perché è raramente vale la pena di venire con una nuova rappresentazione di queste cose - basta non fare che se non si dispone di circostanze che lo richiedono molto specializzata <. / p>
I suggerirebbe di visualizzare il numero in formato esadecimale - è molto più probabile che sia un problema con endianness rispetto ai tipi di dati di un formato speciale, e la stampa dei valori in esadecimale rende più facile capire se questo è il problema .
Sei sicuro che
double (*array)[NElements];
è quello che vuoi? Questo semplice programma:
int main( int argc, char** argv)
{
double (*array)[5];
(*array)[4] = 0;
return 0;
}
si blocca miseramente sulla mia macchina.