Home-brewed code is 100X faster than -[NSScanner scanDecimal:] ??
Home-brewed code is 100X faster than -[NSScanner scanDecimal:] ??
- Subject: Home-brewed code is 100X faster than -[NSScanner scanDecimal:] ??
- From: Jerry Krinock <email@hidden>
- Date: Thu, 3 Feb 2011 08:35:35 -0800
-[NSScanner scanDecimal:] takes an average of 4 milliseconds to scan a short string of decimal digits, which means tens of seconds for thousands of scans, which is unacceptable for my application. Also, excessive memory allocations require a local autorelease pool around each invocation.
Surprisingly, I was able to fix both problem by replacing -scanDecimal: with a rather bone-headed home-brew implementation, using -scanCharactersFromSet:intoString: instead. The home-brew implementation runs 100 to 150 times faster. How can this be?
#import <Cocoa/Cocoa.h>
@interface NSScanner (Speedy)
- (BOOL)scanDecimalNumber:(NSNumber**)number ;
@end
@implementation NSScanner (Speedy)
/*
Bone-headed home-brew implementation
*/
- (BOOL)scanDecimalNumber:(NSNumber**)number {
NSString* string = nil ;
NSCharacterSet* decimalSet ;
decimalSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789-."] ;
BOOL isDecimal = [self scanCharactersFromSet:decimalSet
intoString:&string] ;
if (isDecimal) {
double value ;
value = [string doubleValue] ; // See Note, below
*number = [NSNumber numberWithDouble:value] ;
}
return isDecimal ;
/*
Note. At first, I'd written a more complicated implementation which checked
if the number was an integer and if so used -numberWithInteger instead of
-numberWithDouble, but then found that performance of the current
implementation here is the same. I suppose this is because we've been
doing floating-point calculations in hardware for quite a few years now.
*/
}
@end
NSTimeInterval TestScanner(
NSScanner *scanner,
BOOL homeBrew,
NSInteger exponent) {
// We use a local autorelease pool, otherwise -scanDecimal: starts
// using gigabytes of virtual memory, which makes both the HomeBrew
// and scanDecimal methods take longer, and slow our Mac.
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init] ;
[scanner setScanLocation:0] ;
double checksum = 0.0 ;
NSDate* date = [NSDate date] ;
while (![scanner isAtEnd]) {
NSNumber* number = nil ;
BOOL didScanNumber ;
if (homeBrew) {
didScanNumber = [scanner scanDecimalNumber:&number] ;
}
else {
NSDecimal decimal;
didScanNumber = [scanner scanDecimal:&decimal];
if (didScanNumber) {
number = [NSDecimalNumber decimalNumberWithDecimal:decimal];
}
}
if (didScanNumber) {
double value = [number doubleValue] ;
checksum += value ;
}
else {
[scanner setScanLocation:[scanner scanLocation] + 1] ;
}
}
/* The template includes four numbers: 1, -2, 3.5, -1.5. These
numbers sum to 1. Therefore when we add together the sums
of all the scanned numbers, the "checksum" should be equal
to the number of times that the template appears in the
scanner's string, which is 2^exponent. */
BOOL checksumOK = checksum == pow(2,exponent) ;
NSTimeInterval elapsed = -[date timeIntervalSinceNow] ;
NSLog(@"%@: time = %9.3e seconds checksum = %0.16f (%@)",
homeBrew ? @" Using Home-Brew" : @"Using -scanDecimal:",
elapsed,
checksum,
checksumOK ? @"OK" : @"Error!") ;
[pool release] ;
return elapsed ;
}
#define HOME_BREW YES
#define SCAN_DECIMAL NO
int main(int argc, char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init] ;
NSString* template = @"+int:1 -int:-2 +float:3.5 -float:-1.5 " ;
NSMutableString* s = [template mutableCopy] ;
NSInteger i ;
NSInteger exponent = 9 ;
// Repeat the string 2^exponent times
for (i=0; i<exponent; i++) {
[s appendString:s] ;
}
NSScanner* scanner = [[NSScanner alloc] initWithString:s] ;
NSTimeInterval elapsedScanDecimal = 0.0 ;
NSTimeInterval elapsedHomeBrew = 0.0 ;
NSInteger j ;
for (j=0; j<5; j++) {
elapsedScanDecimal += TestScanner(scanner, SCAN_DECIMAL, exponent) ;
elapsedHomeBrew += TestScanner(scanner, HOME_BREW, exponent) ;
}
NSLog (@"Speed Improvement HomeBrew/scanDecimal: %0.1f",
elapsedScanDecimal/elapsedHomeBrew) ;
[scanner release] ;
[s release] ;
[pool drain] ;
return 0 ;
}_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden