Convert Hex string to IEEE 754 float

2019-09-20 21:31发布

问题:

I am trying to convert a nsstring with hex values into a float value.

NSString *hexString = @"3f9d70a4";

The float value should be = 1.230.

Some ways I have tried to solve this are:

1.NSScanner

-(unsigned int)strfloatvalue:(NSString *)str
{
   float outVal;
   NSString *newStr = [NSString stringWithFormat:@"0x%@",str];
   NSScanner* scanner = [NSScanner scannerWithString:newStr];
   NSLog(@"string %@",newStr);
   bool test = [scanner scanHexFloat:&outVal];
   NSLog(@"scanner result %d = %a (or %f)",test,outVal,outVal);
   return outVal;
}

results:

 string 0x3f9d70a4
 scanner result 1 = 0x1.fceb86p+29 (or 1067282624.000000)

2.casting pointers

NSNumber * xPtr = [NSNumber numberWithFloat:[(NSNumber *)@"3f9d70a4" floatValue]];

result:3.000000

回答1:

What you have is not a "hexadecimal float", as is produced by the %a string format and scanned by scanHexFloat: but the hexadecimal representation of a 32-bit floating-point value - i.e. the actual bits.

To convert this back to a float in C requires messing with the type system - to give you access to the bytes that make up a floating-point value. You can do this with a union:

typedef union { float f; uint32_t i; } FloatInt;

This type is similar to a struct but the fields are overlaid on top of each other. You should understand that doing this kind of manipulation requires you understand the storage formats, are aware of endian order, etc. Do not do this lightly.

Now you have the above type you can scan a hexadecimal integer and interpret the resultant bytes as a floating-point number:

FloatInt fl;
NSScanner *scanner = [NSScanner scannerWithString:@"3f9d70a4"];

if([scanner scanHexInt:&fl.i])        // scan into the i field
{
    NSLog(@"%x -> %f", fl.i, fl.f);   // display the f field, interpreting the bytes of i as a float
}
else
{
    // parse error
}

This works, but again consider carefully what you are doing.

HTH



回答2:

I think a better solutions is a workaround like this :

-(float) getFloat:(NSInteger*)pIndex
{
    NSInteger index = *pIndex;
    NSData* data = [self subDataFromIndex:&index withLength:4];
    *pIndex = index;
    uint32_t hostData = CFSwapInt32BigToHost(*(const uint32_t *)[data bytes]);
    return  *(float *)(&hostData);;
}

Where your parameter is an NSData which rapresents the number in HEX format, and the input parameter is a pointer to the element of NSData.