Преобразовать NSData в примитивную переменную с ieee-754 или с двумя дополнениями? - PullRequest
0 голосов
/ 12 июня 2010

Я новый программист в Obj-C и какао . Я пытаюсь написать каркас, который будет использоваться для чтения двоичных файлов ( Гибкая система транспортировки изображений или FITS двоичные файлы, обычно используемые астрономами). Двоичные данные, которые мне интересно извлечь, могут иметь различные форматы, и я получаю их свойства, читая заголовок файла FITS .

До сих пор мне удавалось создать класс для хранения содержимого файла FITS и изолировать заголовок в объекте NSString и двоичные данные в объекте NSData. Мне также удается написать метод, который позволяет мне извлекать ключевые значения из заголовка, которые очень важны для интерпретации двоичных данных.

Я сейчас пытаюсь преобразовать объект NSData в примитивный массив (массив double, int, short ...). Но здесь я застрял и был бы признателен за любую помощь.

Согласно имеющейся у меня документации о файле FITS , у меня есть 5 возможностей интерпретировать двоичные данные в зависимости от значения ключа 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

Я уже написал код, показанный ниже, чтобы попытаться преобразовать NSData в примитивный массив.

// 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);

}

Однако значение, которое я печатаю в цикле, сильно отличается от ожидаемых значений (по сравнению с использованием официального программного обеспечения FITS). Поэтому я думаю, что Obj-C double не использует соглашение IEEE-754 , а Obj-C int не двойки-дополнение . Я действительно не знаком с этими двумя соглашениями ( IEEE и twos-дополнение ) и хотел бы знать, как я могу сделать это преобразование с Obj-C .

Заранее большое спасибо за любую помощь или информацию.

Ответы [ 4 ]

3 голосов
/ 12 июня 2010

Objective-C использует IEEE-754 с плавающей точкой (как практически во всех системах), а также два целых числа с дополнением. Я думаю, что ваша гипотеза неверна. Может быть, у вас проблемы с порядком байтов?

1 голос
/ 12 июня 2010

Практически во всех системах используются два дополнения и IEEE 754, просто потому, что редко стоит придумывать совершенно новое представление об этих вещах - вы просто не сделаете этого, если у вас нет особых обстоятельств, которые этого требуют.

Я бы посоветовал вам отобразить число в шестнадцатеричном формате - это гораздо более вероятно, что проблема будет иметь порядок с порядком байтов, чем типы данных специального формата, а печать значений в шестнадцатеричном формате облегчает определение, является ли этопроблема.

0 голосов
/ 13 июня 2010

Спасибо большое. Проблема действительно была связана с порядком байтов, и я не знал об этом. Честно говоря, я никогда не знал о порядке байтов, потому что до сих пор никогда не сталкивался с проблемой.

Кстати, я нашел решение, спасибо всем за ваши замечания. Поскольку это может быть полезно для другого разработчика, я предложу код, который позволяет преобразовывать NSData в примитив, который когда-либо являлся типом байтов. Это решение, которое я нахожу (работает с основой и структурой какао в Os X 10.5 и 10.6), и оно может быть не лучшим, поэтому используйте на свой страх и риск;)

// 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;

}

Надеюсь, это может быть полезно.

0 голосов
/ 12 июня 2010

Вы уверены, что

double (*array)[NElements];

это то, что вы хотите? Эта простая программа:

int main( int argc, char** argv)
{
    double (*array)[5];
    (*array)[4] = 0;
    return 0;
}

Сбои на моей машине.

...