-1

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

ribbit
  • 13
  • 6

3 Answers3

3

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

CRD
  • 52,522
  • 5
  • 70
  • 86
  • Thanks so much! I am aware of the endian order. I was never aware of union before. – ribbit May 02 '14 at 03:20
  • i am trying to write the swift 2.0 equivalent for this conversion, but unable to find the swift conversion of the 'union' – Singh Jan 05 '16 at 11:33
  • @mach5 - Swift does not have an equivalent of `union`, it goes against Swift's strong typing model. Your choices include: trying for a Swift solution utilising unsafe pointers; and simply calling (Objective-)C code to do the job. – CRD Jan 05 '16 at 15:58
1

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.

0

So basically you are trying to make an NSString to C's float, there's an old fashion way to do that!

NSString* hexString = @"3f9d70a4";
const char* cHexString = [hexString UTF8String];
long l = strtol(cHexString, NULL, 16);
float f = *((float *) &l);
// f = 1.23

for more detail please see this answer

ytyubox
  • 165
  • 1
  • 15