Objective C: Conversion of large hex to double gives wrong value - ios

I have an issue converting a big hex number 0x500123fb2d414d3d1192a659d4d39dfd to its decimal value
double serialNumberValue = 0;
NSScanner * scanner = [NSScanner scannerWithString:#"0x500123fb2d414d3d1192a659d4d39dfd"];
[scanner scanHexDouble: &serialNumberValue];
NSString* serialNumber = [NSString stringWithFormat: #"%.f", serialNumberValue];
NSLog(#"serialNumber decimal value : %#", serialNumber);
The result I get is: 106344161744262488068834846534090620928 which corresponds to 0x500123FB2D414C000000000000000000 in hex
While the correct conversion is: 106344161744262493917718975250015952381
How can i solve this issue ?
FYI: I need the last 6 digits of the hexadecimal number in its decimal value.

Related

Substring char * in Objective C

I need to substring char* to some length and need to convert to NSString.
char *val substring Length
I tried
NSString *tempString = [NSString stringWithCString:val encoding:NSAsciiStringEncoding];
NSRange range = NSMakeRange (0, length);
NSString *finalValue = [tempString substringWithRange: range];
This works but not for other special character languages like chinese.
If i convert To UTF8Encoding then substring length will mismatch.
Is there any other way to substring the char* then convert to UTF8 encoding?
You have to use the encoding, the string is encoded in.
In your case, you say to interpret the string as ASCII string. ASCII does not have chinese characters. Therefore this cannot work with chinese characters: They are not there.
Likely you have an UTF8 encoded string. But simply switching to UTF8 does not help. Since NSString and OS X/iOS at all encodes 16-Bit Unicode, but extended Unicode has 20 bits, chinese characters needs multiple codes. This has some effects, for example -length returns the number of codes, not the number of chinese characters. However, with -rangeOfComposedCharacterSequencesForRange: you can adjust the range.
For example 𠀖 (CJK unified ideograph-0x20016):
NSString *str = #"𠀖"; // One chinese whatever
NSLog(#"%ld", [str length]); // This are "2" characters
NSRange range = {0, 1}; // Range for the "first" character
NSLog(#"%ld %ld", range.location, range.length); // 0 1
range = [str rangeOfComposedCharacterSequencesForRange:range];
NSLog(#"%ld %ld", range.location, range.length); // 0 2
You can get a better answer, if you add information about the encoding of the string coming in and the required encoding for putting out.
Strings are not UTF8 or whatever strings. Strings are strings. Their storage, their representation in computer memory has an encoding, but they don't have an encoding themselves.
I found the solution for my question
char subString[length+1];
strncpy(subString, val, length);
subString[length] = '\0'; // place the null terminator
NSString *finalString = [NSString stringWithCString: subString encoding:NSUTF8StringEncoding];
I did the char* sub string and UTF8 encoding both.

Convert Hex String to ASCII Format [duplicate]

This question already has an answer here:
NSString containing hex convert to ascii equivalent
(1 answer)
Closed 6 years ago.
I have a Hex string like "000000000100" and I am using the following logic to do ASCII conversion, the output I am receiving is only 1 byte (\x01) But I want the output in the 6 byte format as \x00\x00\x00\x00\x01\x00
-(NSString*) decode
{
string=#"000000000100";
NSMutableString * newString = [[NSMutableString alloc]init];
int i = 0;
while (i < [string length])
{
NSString * hexChar = [string substringWithRange: NSMakeRange(i, 2)];
int value = 0;
sscanf([hexChar cStringUsingEncoding:NSASCIIStringEncoding], "%x", &value);
[newString appendFormat:#"%c", (char)value];
i+=2;
}
return newString;
}
How to do that ?
Let's first directly address your bug: In your code you attempt to add the next byte to your string with:
[newString appendFormat:#"%c", (char)value];
Your problem is that %c produces nothing if the character is a null, so you are appending an empty string and as you found end up with a string with a single byte in it.
You can fix your code by testing for the null and appending a string containing a single null:
if (value == 0)
[newString appendString:#"\0"]; // append a single null
else
[newString appendFormat:#"%c", (char)value];
Second, is this the way to do this?
Other answers have shown you other algorithms, they might be more efficient than yours as they only convert to a C-String once rather than repeatedly extract substrings and convert each one individually.
If and only if performance is a real issue for you you might wish to consider such C-based solutions. You clearly know how to use scanf, but in such a simple case as this you might want to look at digittoint and do the conversion of two hex digits to an integer yourself (value of first * 16 + value of second).
Conversely if you'd like to avoid C and scanf look at NSScanner and scanHexInt/scanHexLongLong - if your strings are never longer than 16 hex digits you can convert the whole string in one go and then produce an NSString from the bytes of the resultant unsigned 64-bit integer.
HTH

NSScanner not scanning long numeric string into number

I have a string "999999999999528106" and I am passing it to NSScanner but the output is not correct. I get 2147483647 as result.
I guess the big size of my string is not fitting into the NSInteger. Any clue
NSScanner *aScanner = [NSScanner scannerWithString:iString];
NSMutableCharacterSet *aCharset = [NSMutableCharacterSet whitespaceAndNewlineCharacterSet];
[aCharset formUnionWithCharacterSet:[NSCharacterSet symbolCharacterSet]];
[aScanner setCharactersToBeSkipped:[aCharset copy]];
NSInteger anIntegerResult = 0;
[aScanner setScanLocation:0];
if ([aScanner scanInteger:&anIntegerResult] && aScanner.isAtEnd)
return #(anIntegerResult);
From the NSScanner documentation:
Skips past excess digits in the case of overflow, so the receiver’s position is past the entire integer representation.
So yes, it's overflowing. You can use scanLongLong: instead.

How can I count decimal digits?

I have to count how many decimal digits are there in a double in Xcode 5. I know that I must convert my double in a NSString, but can you explain me how could I exactly do? Thanks
A significant problem is that a double has a fractional part which has no defined length. If you know you want, say, 3 fractional digits, you could do:
[[NSString stringWithFormat:#"%1.3f", theDoubleNumber] length]
There are more elegant ways, using modulo arithmetic or logarithms, but how elegant do you want to be?
A good method could be to take your double value and, for each iteration, increment a counter, multiply your value by ten, and constantly check if the left decimal part is really near from zero.
This could be a solution (referring to a previous code made by Graham Perks):
int countDigits(double num) {
int rv = 0;
const double insignificantDigit = 8;
double intpart, fracpart;
fracpart = modf(num, &intpart);
while ((fabs(fracpart) > 0.000000001f) && (rv < insignificantDigit))
{
num *= 10;
fracpart = modf(num, &intpart);
rv++;
}
return rv;
}
You could wrap the double in an instance of NSNumber and get an NSString representation from the NSNumber instance. From there, calculating the number of digits after the decimal could be done.
One possible way would be to implement a method that takes a double as an argument and returns an integer that represents the number of decimal places -
- (NSUInteger)decimalPlacesForDouble:(double)number {
// wrap double value in an instance of NSNumber
NSNumber *num = [NSNumber numberWithDouble:number];
// next make it a string
NSString *resultString = [num stringValue];
NSLog(#"result string is %#",resultString);
// scan to find how many chars we're not interested in
NSScanner *theScanner = [NSScanner scannerWithString:resultString];
NSString *decimalPoint = #".";
NSString *unwanted = nil;
[theScanner scanUpToString:decimalPoint intoString:&unwanted];
NSLog(#"unwanted is %#", unwanted);
// the number of decimals will be string length - unwanted length - 1
NSUInteger numDecimalPlaces = (([resultString length] - [unwanted length]) > 0) ? [resultString length] - [unwanted length] - 1 : 0;
return numDecimalPlaces;
}
Test the method with some code like this -
// test by changing double value here...
double testDouble = 1876.9999999999;
NSLog(#"number of decimals is %lu", (unsigned long)[self decimalPlacesForDouble:testDouble]);
results -
result string is 1876.9999999999
unwanted is 1876
number of decimals is 10
Depending on the value of the double, NSNumber may do some 'rounding trickery' so this method may or may not suit your requirements. It should be tested first with an approximate range of values that your implementation expects to determine if this approach is appropriate.

iOS: print unicode character in decimal notation

How would I print a string with 1 letter in a decimal form?
I need to get unique integer for a character and convert it to string.
NSString* letter = #"a"; // ---> to #"97"
unichar c = [letter characterAtIndex:0];
NSString *charAsNum = [NSString stringWithFormat:#"%d",c];

Resources