使用 ieee-754 或二进制补码将 NSData 转换为原始变量?

发布于 2024-09-05 12:32:02 字数 3068 浏览 10 评论 0原文

我是 Obj-Ccocoa 的新程序员。我正在尝试编写一个用于读取二进制文件的框架(灵活图像传输系统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< /strong> int 不是补码。我真的不熟悉这两个约定(IEEEtwos-complement),并且想知道如何使用 Obj-C 进行此转换强>。

预先非常感谢您的任何帮助或信息。

I am new programmer in Obj-C and cocoa. Im a trying to write a framework which will be used to read a binary files (Flexible Image Transport System or FITS binary files, usually used by astronomers). The binary data, that I am interested to extract, can have various formats and I get its properties by reading the header of the FITS file.

Up to now, I manage to create a class to store the content of the FITS file and to isolate the header into a NSString object and the binary data into a NSData object. I also manage to write method which allow me to extract the key values from the header that are very valuable to interpret the binary data.

I am now trying to convert the NSData object into a primitive array (array of double, int, short ...). But, here, I get stuck and would appreciate any help.

According to the documentation I have about the FITS file, I have 5 possibilities to interpret the binary data depending on the value of the BITPIX key:

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 already write the peace of code, shown bellow, to try to convert the NSData into a primitive array.

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

}

However, the value I print in the loop are very different from the expected values (compared using official FITS software). Therefore, I think that the Obj-C double does not use the IEEE-754 convention as well as the Obj-C int are not twos-complement. I am really not familiar with this two convention (IEEE and twos-complement) and would like to know how I can do this conversion with Obj-C.

In advance many thanks for any help or information.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

赴月观长安 2024-09-12 12:32:02

Objective-C 使用 IEEE-754 浮点数(就像几乎每个系统一样)以及二进制补码整数。我认为你的推测是错误的。也许您遇到字节序问题?

Objective-C uses IEEE-754 floats (like practically every system does) as well as two's-complement integers. I think your conjecture is false. Maybe you are having endianness problems?

半葬歌 2024-09-12 12:32:02

几乎所有系统都使用二进制补码和 IEEE 754,仅仅是因为很少值得为这些事物提出全新的表示形式 - 除非您有非常特殊的情况需要它,否则您不会这样做。

我建议您以十六进制显示数字 - 与特殊格式的数据类型相比,这更有可能是字节序问题,并且以十六进制打印值可以更容易地判断这是否是问题。

Virtually all systems use two's complement and IEEE 754, simply because it is rarely worth it to come up with a brand new representation of these things - you just don't do that unless you have very specialized circumstances that require it.

I would suggest you display the number in hexadecimal - it is much more likely to be an issue with endianness than the data types being of a special format, and printing the values in hexadecimal makes it easier to tell if that is the problem.

薄荷梦 2024-09-12 12:32:02

您确定这

double (*array)[NElements];

就是您想要的吗?这个简单的程序:

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

在我的机器上严重崩溃。

Are you sure that

double (*array)[NElements];

is what you want? This simple program:

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

Crashes miserably on my machine.

微暖i 2024-09-12 12:32:02

多谢。这个问题确实与字节序有关,但我没有意识到这一点。老实说,我从来没有真正意识到字节序类型,因为到目前为止,我从未遇到过这个问题。

顺便说一句,我找到了解决方案,谢谢大家的评论。因为它对其他开发人员很有用,所以我将提出一种和平的代码,允许将 NSData 转换为原始类型,无论是什么字节序类型。这是我找到的解决方案(在 Os X 10.5 和 10.6 上使用 Foundation 和 cocoa 框架),它可能不是最好的,因此,使用风险自负;)

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

}

希望这会很有用。

Thanks a lot. The problem was really related to the endian and I was not aware of this. Honestly, I was never really aware of the endian type because, up to now, I was never confronted to the problem.

By the way, I find the solution, thanks all for your remarks. Because it can be useful for other developer, I will propose a peace of code which allow to convert NSData to primitive, what ever the endian type. This is the solution I find (work with the Foundation and cocoa framework on Os X 10.5 and 10.6) and it may not be the best, so, use at your own risk ;)

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

}

Hope this can be useful.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文