Convert first number in an NSString into an Integer? - objective-c
I have an NSString like so:
#"200hello"
or
#"0 something"
What I would like to be able to do is take the first occuring number in the NSString and convert it into an int.
So that #"200hello" would become int = 200.
and #"0 something" would become int = 0.
int value;
BOOL success = [[NSScanner scannerWithString:#"1000safkaj"] scanInteger:&value];
If the number is not always at the beginning:
NSCharacterSet* nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
int value = [[#"adfsdg1000safkaj" stringByTrimmingCharactersInSet:nonDigits] intValue];
Steve Ciarcia once said a single measured result is worth more than a hundred engineers opinions. And so begins the first, and last, "How to get an int value from a NSString" cook-off!
The following are the contenders: (microseconds taken and number of bytes used per match using the incredibly high precision for(x=0; x<100000; x++) {} micro-benchmark that has been handed down through the generations. Time measured via getrusage(), bytes used via malloc_size(). The string to be matched was normalized to 'foo 2020hello' for all cases, except those that required the number to be at the start. All conversions were normalized to 'int'. The two numbers after the time are normalized results relative to the best and worst performers.)
EDIT: These were the original numbers posted, see below for updated numbers. Also, times are from a 2.66 Core2 macbook pro.
characterSet time: 1.36803us 12.5 / 1.00 memory: 64 bytes (via Nikolai Ruhe)
original RKL time: 1.20686us 11.0 / 0.88 memory: 16 bytes (via Dave DeLong)
modified RKL time: 1.07631us 9.9 / 0.78 memory: 16 bytes (me, changed regex to \d+)
scannerScanInt time: 0.49951us 4.6 / 0.36 memory: 32 bytes (via Nikolai Ruhe)
intValue time: 0.16739us 1.5 / 0.12 memory: 0 bytes (via zpasternack)
rklIntValue time: 0.10925us 1.0 / 0.08 memory: 0 bytes (me, modified RKL example)
As I noted somewhere else in this message, I originally threw this in to a unit test harness I use for RegexKitLite. Well, being the unit test harness meant that I was testing with my private copy of RegexKitLite... which just so happened to have a bunch of debug stuff tacked on while tracking down a bug report from a user. The above timing results are approximately equivalent to calling [valueString flushCachedRegexData]; inside the for() {} timing loop (which was essentially what the inadvertent debugging stuff was doing). The following results are from compiling against the latest, unmodified, RegexKitLite available (3.1):
characterSet time: 1.36803us 12.5 / 1.00 memory: 64 bytes (via Nikolai Ruhe)
original RKL time: 0.58446us 5.3 / 0.43 memory: 16 bytes (via Dave DeLong)
modified RKL time: 0.54628us 5.0 / 0.40 memory: 16 bytes (me, changed regex to \d+)
scannerScanInt time: 0.49951us 4.6 / 0.36 memory: 32 bytes (via Nikolai Ruhe)
intValue time: 0.16739us 1.5 / 0.12 memory: 0 bytes (via zpasternack)
rklIntValue time: 0.10925us 1.0 / 0.08 memory: 0 bytes (me, modified RKL example)
This is slightly better than a 50% improvement. If you're willing to live slightly dangerously, you can coax a bit more speed out with the -DRKL_FAST_MUTABLE_CHECK compile time option:
original RKL time: 0.51188us 4.7 / 0.37 memory: 16 bytes using intValue
modified RKL time: 0.47665us 4.4 / 0.35 memory: 16 bytes using intValue
original RKL time: 0.44337us 4.1 / 0.32 memory: 16 bytes using rklIntValue
modified RKL time: 0.42128us 3.9 / 0.31 memory: 16 bytes using rklIntValue
This is usually good for about another 10% boost, and it's fairly safe to use (for more info, see the RKL docs). And while I was at it... why not use the faster rklIntValue too? Is there some kind of prize for beating the native, built in Foundation methods using an external, third party, non-integrated general purpose regex pattern matching engine? Don't believe the hype that "regexes are slow".
END EDIT
The RegexKitLite example can be found at RegexKitLite Fast Hex Conversion. Basically swapped strtoimax for strtol, and added a line of code to skip over leading characters that weren't [+-0-9]. (full disclosure: I'm the author of RegexKitLite)
Both 'scannerScanInt' and 'intValue' suffer from the problem that the number to be extracted must be at the start of the string. I think both will skip any leading white-space.
I modified Dave DeLongs regex from '[^\d]*(\d+)' to just '\d+' because that's all that's really needed, and it manages to get rid of a capture group usage to boot.
So, based on the above data, I offer the following recommendations:
There's basically two different capability classes here: Those that can tolerate extra 'stuff' and still get you the number (characterSet, RegexKitLite matchers, and rklIntValue), and those that basically need the number to be the very first thing in the string, tolerating at most some white space padding at the start (scannerScanInt and intValue).
Do not use NSCharacterClass to do these kinds of things. For the given example, 16 bytes is used to instantiate the first NSCharacterClass, then 32 bytes for the inverted version, and finally 16 bytes for the string result. The fact that a general purpose regex engine outperforms it by a double digit percentage margin while using less memory pretty much seals the deal.
(keep in mind I wrote RegexKitLite, so take the following with whatever sized grain of salt you feel is appropriate).
RegexKitLite turns in good times and uses the smallest amount of memory possible considering the fact that it's returning a NSString object. Since it uses a LRU cache internally for all the ICU regex engine stuff, those costs get amortized over time and repeated uses. It also takes seconds to change the regex if the need comes up (hex values? hex floats? Currencies? Dates? No problem.)
For the simple matchers, it should be obvious that you definitely should NOT use NSScanner to do these kinds of things. Using NSScanner to do a 'scanInt:' is no different than just calling [aString intValue]. The produce the same results with the same caveats. The difference is NSScanner takes FIVE times longer to the same thing, while wasting 32 bytes of memory in the process.... while [aString intValue] (probably) doesn't require one byte of memory to perform its magic- it probably just calls strtoimax() (or an equivalent) and since it has direct access to the pointer holding the strings contents....
The final one is 'rklIntValue', which again is just a slightly tweaked version of what you can find at (the 'RegexKitLite Fast Hex Conversion' link above, stackoverflow won't let me post it twice). It uses CoreFoundation to try to get direct access to the strings buffer, and failing that, allocates some space off the stack and copies a chunk of the string to that buffer. This takes all of, oh, three instructions on the CPU, and is fundamentally impossible to 'leak' like a malloc() allocation. So it uses zero memory and goes very, very fast. As an extra bonus, you pass to strtoXXX() the number base of the string to convert. 10 for decimal, 16 for hex (automatically swallowing a leading 0x if present), or 0 for automagic detection. It's a trivial, single line of code to skip the pointer over any 'uninteresting' characters until you get to what you want (I choose -,+, and 0-9). Also trivial to swap in something like strtod() if you need to parse double values. strtod() converts just about any valid floating point text: NAN, INF, hex floats, you name it.
EDIT:
Per request of the OP, here's a trimmed and minified version of the code that I used to perform the tests. One thing of note: While putting this together, I noticed that Dave DeLongs original regex didn't quite work. The problem is in the negated character set- meta-character sequences inside sets (ie, [^\d]+) mean the literal character, not the special meaning they have outside the character set. Replaced with [^\p{DecimalNumber}]*, which has the intended effect.
I originally bolted this stuff to a RegexKitLite unit test harness, so I left some bits and pieces for GC in. I forgot all about this, but the short version of what happens when GC is turned on is that times of everything BUT RegexKitLite double (that is, takes twice as long). RKL only takes about 75% longer (and that took an enormous, non-trivial amount of effort to get when I was developing it). The rklIntValue time stays exactly the same.
Compile with shell% gcc -DNS_BLOCK_ASSERTIONS -mdynamic-no-pic -std=gnu99 -O -o stackOverflow stackOverflow.m RegexKitLite.m -framework Foundation -licucore -lauto
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <objc/objc-auto.h>
#include <malloc/malloc.h>
#import <Foundation/Foundation.h>
#import "RegexKitLite.h"
static double cpuTimeUsed(void);
static double cpuTimeUsed(void) {
struct rusage currentRusage;
getrusage(RUSAGE_SELF, ¤tRusage);
double userCPUTime = ((((double)currentRusage.ru_utime.tv_sec) * 1000000.0) + ((double)currentRusage.ru_utime.tv_usec)) / 1000000.0;
double systemCPUTime = ((((double)currentRusage.ru_stime.tv_sec) * 1000000.0) + ((double)currentRusage.ru_stime.tv_usec)) / 1000000.0;
double CPUTime = userCPUTime + systemCPUTime;
return(CPUTime);
}
#interface NSString (IntConversion)
-(int)rklIntValue;
#end
#implementation NSString (IntConversion)
-(int)rklIntValue
{
CFStringRef cfSelf = (CFStringRef)self;
UInt8 buffer[64];
const char *cptr, *optr;
char c;
if((cptr = optr = CFStringGetCStringPtr(cfSelf, kCFStringEncodingMacRoman)) == NULL) {
CFRange range = CFRangeMake(0L, CFStringGetLength(cfSelf));
CFIndex usedBytes = 0L;
CFStringGetBytes(cfSelf, range, kCFStringEncodingUTF8, '?', false, buffer, 60L, &usedBytes);
buffer[usedBytes] = 0U;
cptr = optr = (const char *)buffer;
}
while(((cptr - optr) < 60) && (!((((c = *cptr) >= '0') && (c <= '9')) || (c == '-') || (c == '+'))) ) { cptr++; }
return((int)strtoimax(cptr, NULL, 0));
}
#end
int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
#ifdef __OBJC_GC__
objc_start_collector_thread();
objc_clear_stack(OBJC_CLEAR_RESIDENT_STACK);
objc_collect(OBJC_EXHAUSTIVE_COLLECTION | OBJC_WAIT_UNTIL_DONE);
#endif
BOOL gcEnabled = ([objc_getClass("NSGarbageCollector") defaultCollector] != NULL) ? YES : NO;
NSLog(#"Garbage Collection is: %#", gcEnabled ? #"ON" : #"OFF");
NSLog(#"Architecture: %#", (sizeof(void *) == 4UL) ? #"32-bit" : #"64-bit");
double startTime = 0.0, csTime = 0.0, reTime = 0.0, re2Time = 0.0, ivTime = 0.0, scTime = 0.0, rklTime = 0.0;
NSString *valueString = #"foo 2020hello", *value2String = #"2020hello";
NSString *reRegex = #"[^\\p{DecimalNumber}]*(\\d+)", *re2Regex = #"\\d+";
int value = 0;
NSUInteger x = 0UL;
{
NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *nonDigits = [digits invertedSet];
NSScanner *scanner = [NSScanner scannerWithString:value2String];
NSString *csIntString = [valueString stringByTrimmingCharactersInSet:nonDigits];
NSString *reString = [valueString stringByMatching:reRegex capture:1L];
NSString *re2String = [valueString stringByMatching:re2Regex];
[scanner scanInt:&value];
NSLog(#"digits : %p, size: %lu", digits, malloc_size(digits));
NSLog(#"nonDigits : %p, size: %lu", nonDigits, malloc_size(nonDigits));
NSLog(#"scanner : %p, size: %lu, int: %d", scanner, malloc_size(scanner), value);
NSLog(#"csIntString : %p, size: %lu, '%#' int: %d", csIntString, malloc_size(csIntString), csIntString, [csIntString intValue]);
NSLog(#"reString : %p, size: %lu, '%#' int: %d", reString, malloc_size(reString), reString, [reString intValue]);
NSLog(#"re2String : %p, size: %lu, '%#' int: %d", re2String, malloc_size(re2String), re2String, [re2String intValue]);
NSLog(#"intValue : %d", [value2String intValue]);
NSLog(#"rklIntValue : %d", [valueString rklIntValue]);
}
for(x = 0UL, startTime = cpuTimeUsed(); x < 100000UL; x++) { value = [[valueString stringByTrimmingCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] intValue]; } csTime = (cpuTimeUsed() - startTime) / (double)x;
for(x = 0UL, startTime = cpuTimeUsed(); x < 100000UL; x++) { value = [[valueString stringByMatching:reRegex capture:1L] intValue]; } reTime = (cpuTimeUsed() - startTime) / (double)x;
for(x = 0UL, startTime = cpuTimeUsed(); x < 100000UL; x++) { value = [[valueString stringByMatching:re2Regex] intValue]; } re2Time = (cpuTimeUsed() - startTime) / (double)x;
for(x = 0UL, startTime = cpuTimeUsed(); x < 100000UL; x++) { value = [valueString rklIntValue]; } rklTime = (cpuTimeUsed() - startTime) / (double)x;
for(x = 0UL, startTime = cpuTimeUsed(); x < 100000UL; x++) { value = [value2String intValue]; } ivTime = (cpuTimeUsed() - startTime) / (double)x;
for(x = 0UL, startTime = cpuTimeUsed(); x < 100000UL; x++) { [[NSScanner scannerWithString:value2String] scanInt:&value]; } scTime = (cpuTimeUsed() - startTime) / (double)x;
NSLog(#"csTime : %.5lfus", csTime * 1000000.0);
NSLog(#"reTime : %.5lfus", reTime * 1000000.0);
NSLog(#"re2Time: %.5lfus", re2Time * 1000000.0);
NSLog(#"scTime : %.5lfus", scTime * 1000000.0);
NSLog(#"ivTime : %.5lfus", ivTime * 1000000.0);
NSLog(#"rklTime: %.5lfus", rklTime * 1000000.0);
[NSString clearStringCache];
[pool release]; pool = NULL;
return(0);
}
If the int value is always at the beginning of the string, you can simply use intValue.
NSString *string = #"123hello";
int myInt = [string intValue];
I would probably use a regular expression (implemented with the stellar RegexKitLite). Then it'd be something like:
#import "RegexKitLite.h"
NSString * original = #"foo 220hello";
NSString * number = [original stringByMatching:#"[^\\d]*(\\d+)" capture:1];
return [number integerValue];
The regex #"[^\d]*(\d+)" means "any number of non-numeric characters followed by at least one numeric character".
I came up with my own answer, potentially faster and easier than the others provided.
My answer does assume you know the position the number begins and ends though...
NSString *myString = #"21sss";
int numberAtStart = [[myString substringToIndex:2] intValue];
You can get to to work the other way too:
NSString *myString = #"sss22";
int numberAtEnd = [[myString substringFromIndex:3] intValue];
int i;
NSString* string;
i = [string intValue];
Related
Wildly varying hashing performance with CFSet and CFDictionary on OS X
When using CFSet and CFDictionary configured with custom callbacks to use integers as their keys, I've noticed some wildly varying performance of their internal hashing implementation. I'm using 64 bit integers (int64_t) with a range of roughly 1 - 1,000,000. While profiling my application with, I noticed that every so often, a certain combination of factors would produce unusually poor performance. Looking at Instruments, CFBasicHash was taking much longer than usual. After a bunch of investigating, I finally narrowed things down to a set of 400,000 integers that, when added to a CFSet or CFDictionary cause terrible performance with hashing. The hashing implementation in CFBasicHash.m is beyond my understating for a problem like this, so I was wondering if anyone had any idea why such a completely random set of integers could cause such dreadful performance. The following test application will output an average iteration time of 37ms for adding sequential integers to a set, but an average run time of 3622ms when adding the same number of integers but from the problematic data set. (And if you insert the same number of completely random integers, then performance is much closer to 37ms. As well, adding these problematic integers to an std::map or std:set produces acceptable performance.) #import <Foundation/Foundation.h> extern uint64_t dispatch_benchmark(size_t count, void (^block)(void)); int main(int argc, char *argv[]) { #autoreleasepool { NSString *data = [NSString stringWithContentsOfFile:#"Integers.txt" encoding:NSUTF8StringEncoding error:NULL]; NSArray *components = [data componentsSeparatedByString:#","]; NSInteger count = components.count; int64_t *numbers = (int64_t *)malloc(sizeof(int64_t) * count); int64_t *sequentialNumbers = (int64_t *)malloc(sizeof(int64_t) * count); for (NSInteger c = 0; c < count; c++) { numbers[c] = [components[c] integerValue]; sequentialNumbers[c] = c; } NSLog(#"Beginning test with %# numbers...", #(count)); // Test #1 - Loading sequential integers uint64_t t1 = dispatch_benchmark(10, ^{ CFMutableSetRef mutableSetRef = CFSetCreateMutable(NULL, 0, NULL); for (NSInteger c = 0; c < count; c++) { CFSetAddValue(mutableSetRef, (const void *)sequentialNumbers[c]); } NSLog(#"Sequential iteration completed with %# items in set.", #(CFSetGetCount(mutableSetRef))); CFRelease(mutableSetRef); }); NSLog(#"Sequential Numbers Average Runtime: %llu ms", t1 / NSEC_PER_MSEC); NSLog(#"-----"); // Test #2 - Loading data set uint64_t t2 = dispatch_benchmark(10, ^{ CFMutableSetRef mutableSetRef = CFSetCreateMutable(NULL, 0, NULL); for (NSInteger c = 0; c < count; c++) { CFSetAddValue(mutableSetRef, (const void *)numbers[c]); } NSLog(#"Dataset iteration completed with %# items in set.", #(CFSetGetCount(mutableSetRef))); CFRelease(mutableSetRef); }); NSLog(#"Dataset Average Runtime: %llu ms", t2 / NSEC_PER_MSEC); free(sequentialNumbers); free(numbers); } } Example output: Sequential Numbers Average Runtime: 37 ms Dataset Average Runtime: 3622 ms The integers are available here: Gist (Integers.txt) or Dropbox (Integers.txt) Can anyone help explain what is "special" about the given integers that might cause such a degradation in the hashing implementation used by CFSet and CFDictionary?
Objective-C: Flooring to 3 decimals correctly
I am trying to floor a float value to the third decimal. For example, the value 2.56976 shall be 2.569 not 2.570. I searched and found answers like these: floor double by decimal place Such answers are not accurate. For example the code: double value = (double)((unsigned int)(value * (double)placed)) / (double)placed can return the value - 1 and this is not correct. The multiplication of value and placed value * (double)placed) could introduce something like: 2100.999999996. When changed to unsigned int, it becomes 2100 which is wrong (the correct value should be 2101). Other answers suffer from the same issue. In Java, you can use BigDecimal which saves all that hassels. (Note: of course, rounding the 2100.9999 is not an option as it ruins the whole idea of flooring to "3 decimals correctly")
The following code should work: #include <stdio.h> #include <math.h> int main(void) { double value = 1.23456; double val3; val3 = floor(1000.0 * value + 0.0001) * 0.001; // add 0.0001 to "fix" binary representation problem printf("val3 is %.8f; the error is %f\n", val3, 1.234 - val3); } this prints out val3 is 1.23400000; the error is 0.000000 If there are any residual errors, it comes about from the fact that floating point numbers cannot necessarily be represented exactly - the idea behind BigDecimal and things like that is to work around that in a very explicit way (for example by representing a number as its digits, rather than a binary representation - it's less efficient, but maintains accuracy)
I had to consider a solution involving NSString and it worked like a charm. Here is the full method: - (float) getFlooredPrice:(float) passedPrice { NSString *floatPassedPriceString = [NSString stringWithFormat:#"%f", passedPrice]; NSArray *floatArray = [floatPassedPriceString componentsSeparatedByString:#"."]; NSString *fixedPart = [floatArray objectAtIndex:0]; NSString *decimalPart = #""; if ([floatArray count] > 1) { NSString *decimalPartWhole = [floatArray objectAtIndex:1]; if (decimalPartWhole.length > 3) { decimalPart = [decimalPartWhole substringToIndex:3]; } else { decimalPart = decimalPartWhole; } } NSString *wholeNumber = [NSString stringWithFormat:#"%#.%#", fixedPart, decimalPart]; return [wholeNumber floatValue]; }
For example, the value 2.56976 shall be 2.569 not 2.570 Solution is has simple as that : double result = floor(2.56976 * 1000.0) / 1000.0; I don't know why you search complication... this works perfectly, doesn't need to pass by some unsigned int or other + 0.0001 or whatever. Important note : NSLog(#"%.4f", myDouble); Actually do a round on your variable. So it's improper to believe you can floor with a %.Xf
Convert really large decimal string to hex?
I've got a really large decimal number in an NSString, which is too large to fit into any variable including NSDecimal. I was doing the math manually, but if I can't fit the number into a variable then I can't be dividing it. So what would be a good way to convert the string? Example Input: 423723487924398723478243789243879243978234 Output: 4DD361F5A772159224CE9EB0C215D2915FA I was looking at the first answer here, but it's in C# and I don't know it's objective C equivalent. Does anyone have any ideas that don't involve using an external library?
If this is all you need, it's not too hard to implement, especially if you're willing to use Objective-C++. By using Objective-C++, you can use a vector to manage memory, which simplifies the code. Here's the interface we'll implement: // NSString+BigDecimalToHex.h #interface NSString (BigDecimalToHex) - (NSString *)hexStringFromDecimalString; #end To implement it, we'll represent an arbitrary-precision non-negative integer as a vector of base-65536 digits: // NSString+BigDecimalToHex.mm #import "NSString+BigDecimalToHex.h" #import <vector> // index 0 is the least significant digit typedef std::vector<uint16_t> BigInt; The "hard" part is to multiply a BigInt by 10 and add a single decimal digit to it. We can very easily implement this as long multiplication with a preloaded carry: static void insertDecimalDigit(BigInt &b, uint16_t decimalDigit) { uint32_t carry = decimalDigit; for (size_t i = 0; i < b.size(); ++i) { uint32_t product = b[i] * (uint32_t)10 + carry; b[i] = (uint16_t)product; carry = product >> 16; } if (carry > 0) { b.push_back(carry); } } With that helper method, we're ready to implement the interface. First, we need to convert the decimal digit string to a BigInt by calling the helper method once for each decimal digit: - (NSString *)hexStringFromDecimalString { NSUInteger length = self.length; unichar decimalCharacters[length]; [self getCharacters:decimalCharacters range:NSMakeRange(0, length)]; BigInt b; for (NSUInteger i = 0; i < length; ++i) { insertDecimalDigit(b, decimalCharacters[i] - '0'); } If the input string is empty, or all zeros, then b is empty. We need to check for that: if (b.size() == 0) { return #"0"; } Now we need to convert b to a hex digit string. The most significant digit of b is at the highest index. To avoid leading zeros, we'll handle that digit specially: NSMutableString *hexString = [NSMutableString stringWithFormat:#"%X", b.back()]; Then we convert each remaining base-65536 digit to four hex digits, in order from most significant to least significant: for (ssize_t i = b.size() - 2; i >= 0; --i) { [hexString appendFormat:#"%04X", b[i]]; } And then we're done: return hexString; } You can find my full test program (to run as a Mac command-line program) in this gist.
Generating Combinatorics of Large Numbers in Obj-C
tl;dr: How should I be dealing with numbers like 20! * 20! in Objective-C? I'm learning Objective-C by working through Project Euler. It's been quite fun, but one problem I've been running in to is working with arbitrarily large numbers. I'm still pretty green on these things, so I don't know why something like, say, Python, handles large numbers with ease compared to Obj-C. Take for example Problem 15: Starting in the top left corner of a 2 x 2 grid, there are 6 routes (without backtracking) to the bottom right corner. How many routes are there through a 20 x 20 grid? That's easy. Using combinatorics: (20+20)! / 20!(20!) -> 815915283247897734345611269596115894272000000000 / 5919012181389927685417441689600000000 -> 137846528820 In Python: import math print math.factorial(40) / (math.factorial(20) * math.factorial(20)) In Objective-C, though? I have't yet found a way to force such a large numbers through. Using the 2 x 2 example works fine. I can get 9C4 = 126, as it should be. But how should I be dealing with numbers like 20!? I've dallied with trying to use NSDecimalNumber, which appears to support more numerals per number, assuming you can convert it to Mantissa x Exponent and don't mind loss of precision, but that didn't prove to be too useful, as I couldn't figure out how to have Obj-C create a Mantissa from a %llu and I do mind loss of precision. The code I have so far properly generates the factorials, as it appears unsigned long long handles values so large, but chokes up on x * y, and thus getCombinatoricOf:20 and:20 returns 1. #import "Problem15.h" #implementation Problem15 - (unsigned long long)factorial:(NSNumber *)number { unsigned long long temp = 1; for (int i = [number intValue]; i > 0; i--) { temp *= i; } return temp; } - (unsigned long long)getCombinatorcOf:(NSNumber *)x and:(NSNumber *)y { NSNumber *n = #([x intValue] + [y intValue]); NSNumber *n_factorial = #([self factorial:n]); NSNumber *x_factorial = #([self factorial:x]); NSNumber *y_factorial = #([self factorial:y]); return ([n_factorial unsignedLongLongValue] / ([x_factorial unsignedLongLongValue] * [y_factorial unsignedLongLongValue])); } - (NSString *)answer { NSNumber *x = #5; NSNumber *y = #4; unsigned long long answer = [self getCombinatoricOf:x and:y]; return [NSString stringWithFormat:#"\n\nProblem 15: \nHow many routes are there through a 20 x 20 grid? \n%llu", answer]; } #end
It's not Objective-C, but you could just use GMP just as an ordinary C library. There are also Objective-C wrappers fo GMP, like GMPInt.
Arbitrary precision bit manipulation (Objective C)
I need to do bit operations on representations of arbitrary precision numbers in Objective C. So far I have been using NSData objects to hold the numbers - is there a way to bit shift the content of those? If not, is there a different way to achieve this?
Using NSMutableData you can fetch the byte in a char, shift your bits and replace it with -replaceBytesInRange:withBytes:. I don't see any other solution except for writing your own date holder class using a char * buffer to hold the raw data.
As you'll have spotted, Apple doesn't provide arbitrary precision support. Nothing is provided larger than the 1024-bit integers in vecLib. I also don't think NSData provides shifts and rolls. So you're going to have to roll your own. E.g. a very naive version, which may have some small errors as I'm typing it directly here: #interface NSData (Shifts) - (NSData *)dataByShiftingLeft:(NSUInteger)bitCount { // we'll work byte by byte int wholeBytes = bitCount >> 3; int extraBits = bitCount&7; NSMutableData *newData = [NSMutableData dataWithLength:self.length + wholeBytes + (extraBits ? 1 : 0)]; if(extraBits) { uint8_t *sourceBytes = [self bytes]; uint8_t *destinationBytes = [newData mutableBytes]; for(int index = 0; index < self.length-1; index++) { destinationBytes[index] = (sourceBytes[index] >> (8-extraBits)) | (sourceBytes[index+1] << extraBits); } destinationBytes[index] = roll >> (8-extraBits); } else /* just copy all of self into the beginning of newData */ return newData; } #end Of course, that assumes the number of bits you want to shift by is itself expressible as an NSUInteger, amongst other sins.