Working with big numbers in Objective-C? - objective-c

I need to convert values like 1393443048683555715 to HEX. But, first of all, i cann't display it as decimal using NSLog(), for example.
Ok, it works:
NSLog(#"%qu", 1393443048683555706);
But what about converting to HEX. What type i have to use to store this big value?
NSLog([NSString stringWithFormat: #"%x", 1393443048683555706]);
// result eb854b7a. It's incorrect result!
but i forgot to say that this big number represented as string #"1393443048683555706" (not int)

You can use %qi and %qu format specifiers with NSLog to display 64-bit integers. Your constant appears to fit in 64-bit signed number, with the limits of:
[−9223372036854775808 to 9223372036854775807]

The "x" format specifier is for 32-bit numbers; you need to use either "qx" or "qX" (depending on whether you want the letter values to be uppercase or not). These are the formatters for unsigned long long values, see:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW1
Next, you should not pass a string as you have done above directly to NSLog - this can cause a crash.
NSLog(string); // bad!!
NSLog(#"%#", string); // good
So if your value comes as a string, you'll want to do this:
NSString *longNumber = #"1393443048683555706";
NSLog(#"%qx", [longNumber longLongValue]);
If the string value can't be coerced to a number, longLongValue will return 0. I'll leave it to you do handle the error (and bounds) checking - see NSString for details.
If you want to save the hex value as a string, do this:
NSString *hexRepresentation = [NSString stringWithFormat:#"%qx", [longNumber longLongValue]];
Again, best to take care for error handling.

Related

Get invisible decimal value in NSString objc

I have a string with random names with an invisible decimal value as prefix . The decimal = the names length. I need to retrieve the names. Obviously they are of different length. I want the names in an array so my idea is to use stringByReplacingOccurrencesOfString:withString. I implement the word "trunk" at the beginning and end of names. Though I am having trouble accessing the index corresponding at the end of the name (decimal value), here is my code :
trimmed1 = [[trimmed1 stringByReplacingOccurrencesOfString:sp withString:#"trunk"]mutableCopy];
NSString *trunk = #"trunk%d";// add the ghost decimal at the end of prefix in order to get its value;
NSRange range =[trimmed1 rangeOfString:trunk];
int ghost= [trunk characterAtIndex:5];
NSMutableString *mu = [NSMutableString stringWithString:trimmed1];
[mu insertString : #"trunk" atIndex :range.location+range.length+ ghost];
I get the error [__NSCFString insertString:atIndex:]: Range or index out of bounds.
You are misunderstanding what %d means.
In a format used for creating a string it means "insert the value of an integer argument formatted as a string".
When matching one string against another it means "match the characters %d", I.e. it is not special in anyway.
You are getting an error as your string does not contain the characters "trunk%d". If you check the return value of rangeOfString: you will find it is returning a failure indication - read the documentation for how to test for that value.
For the simple task of matching an arbitrary decimal number trying looking at the NSString method rangeOfCharactersFromSet:.
You can also solve this problem with the classes NSScanner and NSRegularExpression.
HTH

What does stringWithFormat:#"%1$#%2$d" do?

stack = [NSString stringWithFormat:#"%1$#%2$d", stack, number];
I'm following a Xcode calculator tutorial, and I'm not too sure what does the %1$#%2$d represents. Please guide me.
%# says the argument is an Objective-C object and it sends one of the description selectors to get the string that will be inserted into the final string.
%1$# says the same thing, but specifies the first argument.
%d is a signed, 32-bit integer.
%2$d specifies the second argument is a signed, 32-bit integer.
This format is used to explicitly select which argument should be replaced in the string so 1$ is for the first argument, 2$ for the 2nd etc...
The '#' is for ObjC objects (which in general displayes an object's description), and 'd' is for integers
In this case it could also be written simply as :
stack = [NSString stringWithFormat:#"%#%d", stack, number];
I assume you know what %# and %d mean. By default, the first specifier(such as %#) will be replaced by the value of the first argument in argument list, and so on. However, n$ gives you the power to specify the argument at which position you want to use its value to replace the specifier containing n$.
In fact, a simple example is much clearer:
NSString *aString = #"ultimate answer";
int anInteger = 42;
NSLog(#"The %# is %d.", aString, anInteger); // The ultimate answer is 42.
NSLog(#"The %1$# is %2$d.", aString, anInteger); // The ultimate answer is 42.
NSLog(#"%2$d is the %1$#.", aString, anInteger); // 42 is the ultimate answer.
[NSString stringWithFormat:#"%1$#%2$d", stack, number];
breaks down logically to mean you want a string (you get that from string with format), displaying two items (you can see that from the items after the string, and the number of % symbols in the format.
%1$#%2$d is for two items, you can break them by the %, %1 and %2 mean first and second.
%1$# - # represents an object that wil be translated to a string
%2$d - d represents a decimal.

How to convert NSDecimalNumber to double

I have a value being stored as an NSDecimalNumber and when I convert it to a double it's losing precision.
For the current piece of data I'm debugging against, the value is 0.2676655. When I send it a doubleValue message, I get 0.267665. It's truncating instead of rounding and this is wreaking havoc with some code that uses hashes to detect data changes for a syncing operation.
The NSDecimalNumber instance comes from a third-party framework so I can't just replace it with a primitive double. Ultimately it gets inserted into an NSMutableString so I'm after a string representation, however it needs to be passed through a format specifier of "%.6lf", basically I need six digits after the decimal so it looks like 0.267666.
How can I accomplish this without losing precision? If there's a good way to format the NSDecimalNumber without converting to a double that will work as well.
The NSDecimalNumber instance comes from a third-party framework so I
can't just replace it with a primitive double.
Yes you can. NSDecimalNumber is an immutable subclass of NSNumber, which is a little too helpful when it comes to conversion:
double myDub = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithDouble:((double)0.2676655)] doubleValue]];
Ultimately it gets inserted into an NSMutableString so I'm after a
string representation, however it needs to be passed through a format
specifier of "%.6lf", basically I need six digits after the decimal so
it looks like 0.267666.
Double precision unfortunately does not round, but getting a string value that's off by one-millionth is not that big of a deal (I hope):
NSDecimalNumber *num = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithDouble:((double)0.2676655)] decimalValue]];
NSString *numString = [NSString stringWithFormat:#"%.6lf", [num doubleValue]];
NSLog(#"%#",numString);
I think that your are on a wrong path and somewhere lost in what to do.
First of all, keep in mind that in objective-c lond double is not supported, so you might better want to use something like %f instead of %lf.
[to be found in the documentation library under "Type encodings" of the objective c runtime programming guide]
Then I would rather expect that the value is show as being truncated, as the doubleValue returns an approximate value but the range you are using is still within the correct range.
You should use a simple formatter instead of moving numbers around, like:
// first line as an example for your real value
NSDecimalNumber *value = [NSDecimalNumber decimalNumberWithString:#"0.2676655"];
NSNumberFormatter *numFmt = [[NSNumberFormatter alloc] init];
[numFmt setMaximumFractionDigits:6];
[numFmt setMinimumFractionDigits:6];
[numFmt setMinimumIntegerDigits:1];
NSLog(#"Formatted number %#",[numFmt stringFromNumber:value]);
This has another benefit of using a locale aware formatter if desired. The result of the number formatter is the desired string.

Objective-C Converting an integer to a hex value

I've got a dictionary initialized like so...
keyDictionary = [[NSDictionary dictionaryWithObjects:values forKeys:keys]retain];
where keys is an NSArray of the alphabet and other characters and values is an NSArray of unsigned chars, which are the USB hex keycodes for those characters.
The USB key codes are hex values that range from 0x04 to 0xE7. I'm trying to create a map between these two depending on what key is pressed on the keyboard.
The values array is created like so...
NSArray *values = [NSArray arrayWithObjects:
[NSNumber numberWithUnsignedChar:0x04]/*A*/,
[NSNumber numberWithUnsignedChar:0x05]/*B*/, /*ETC*/];
So ideally when I run this code...
where character == #"I"
- (uint8) getUSBCode:(NSString *)character
{
NSNumber *val = [keyDictionary objectForKey:character];
return (uint8)[val unsignedCharValue];
}
I would expect to get back 0x0C, but I'm getting 12 back as an int (which after I thought about it, makes sense). I need the hex value preserved. I do NOT need a string value. I need a straight conversion to the hex value or a better way to store
uint8 is just a typedef unsigned char.
EDIT I was not clear when I posted this earlier. Here's what I need.
I need the hex value of these codes because they are being sent over the internal company network. In addition, the pressed key's value is being converted from big endian (or little, it's escaping me right now which one it is) to the other, then being transmitted over an internal network. I understand that these values are stored in binary, but I need to transmit them in hex.
Also, I stated I was getting 12 back from the function. I was reading 12 from the debugger, not actually getting the value. That might be why I was getting confused.
12 (in base 10) is 0x0c.
If you want to print it out in hex, use the %x format specifier e.g.
NSLog(#"Hex value of char is 0x%02x", (unsigned int) c);
If you want to see it in hex in the debugger (assuming Xcode 3.2.x) right click on the variable and select hexadecimal as the format.
You know that an int is stored in binary (i.e. the 'hex' value is always and never preserved), so I'm interpreting your question as pertaining to printing to the screen.
You should be able to use a format specifier for that -- something like %0x.
The value that's returned from your -getUSBCode: method isn't two decimal digits, it's one eight-bit byte. Both "12" and "0x0C" are strings that represent that byte's value, so saying you want "0x0C" but don't want a string is a contradiction.

Objective-C and scanning an integer or character to a hex representation

NSScanner has the instance method -scanHexInt: for converting a hexadecimal string representation of an int to an int. I'd like to invert this: I'd like a method that takes an int and returns a hexadecimal representation.
Is there a ready made method in the docs?
[To be more relevant, I'd like to take a string comprising a single kanji and return its unicode point.]
If you check the documentation on string format specifiers, you'll see that there are several specifiers you can use to get a hexadecimal string representation of a number. For instance, you could use:
[NSString stringWithFormat:#"%x", foo]