Swiftチュートリアルで遊んでいたときに、特定のisPrime
が素数であるかどうかを確認するためのカスタムInt
メソッドを書き始めました。
それを書いた後、私はそれが正しく機能していることに気づきましたが、いくつかのかなり大きな数(まだInt.max
よりはるかに低い)でisPrime
を実行するのが少し遅いことに気付きました。
そのため、同じコードをobjcで記述したところ、コードははるかに高速に実行されました(66倍)。
これがSwiftコードです:
class Swift {
class func isPrime(n:Int) -> Bool {
let sqr : Int = Int(sqrt(Double(n))) + 1
for i in 2...sqr {
if n % i == 0 {
return false
}
}
return true;
}
class func primesInRange(start:Int, end:Int) -> Int[] {
var primes:Int[] = Int[]()
for n in start...end {
if self.isPrime(n) {
primes.append(n)
}
}
return primes;
}
}
そして、objcコード:
@implementation Utils
+ (BOOL)isPrime:(NSUInteger)n {
NSInteger sqr = (NSUInteger)(sqrt(n))+1;
for (NSUInteger i = 2; i < sqr; ++i) {
if (n % i == 0) {
return false;
}
}
return YES;
}
+ (NSArray*)primesInRange:(NSUInteger)start end:(NSUInteger)end {
NSMutableArray* primes = [NSMutableArray array];
for (NSUInteger i = start; i <= end; ++i) {
if ([self isPrime:i])
[primes addObject:@(i)];
}
return primes.copy;
}
@end
そしてmain.Swift
で:
let startDateSwift = NSDate.date()
let swiftPrimes = Swift.primesInRange(1_040_101_022_000, end: 1_040_101_022_200)
let elapsedSwift = NSDate.date().timeIntervalSinceDate(startDateSwift)*1000
let startDateObjc = NSDate.date()
let objcPrimes = Utils.primesInRange(1_040_101_022_000, end: 1_040_101_022_200)
let elapsedObjc = NSDate.date().timeIntervalSinceDate(startDateObjc)*1000
println("\(swiftPrimes) took: \(elapsedSwift)ms");
println("\(objcPrimes) took: \(elapsedObjc)ms");
これにより、次のものが生成されます。
[1040101022027, 1040101022039, 1040101022057, 1040101022099, 1040101022153] took: 3953.82004976273ms
[1040101022027, 1040101022039, 1040101022057, 1040101022099, 1040101022153] took: 66.4250254631042ms
ここでextension
のInt
を使用して、数が素数であるかどうかを確認できたはずですが、両方のコードを非常に類似させたいと思いました。
このSwiftコードが非常に遅い理由を誰かに教えてもらえますか?66x係数はかなり怖く、範囲をインクリメントするにつれて悪化するだけです。
Swiftコンパイラのコード生成の最適化レベルは次のとおりです(ビルド設定にあります)。
[-Onone] no optimizations, the default for debug.
[-O] perform optimizations, the default for release.
[-Ofast] perform optimizations and disable runtime overflow checks and runtime type checks.
あなたのコードを使用して、私は最適化のさまざまなレベルでこれらの時間を取得しました:
[-Onone]
Swift: 6110.98903417587ms
Objc: 134.006023406982ms
[-O]
Swift: 89.8249745368958ms
Objc: 85.5680108070374ms
[-Ofast]
Swift: 77.1470069885254ms
Objc: 76.3399600982666ms
-Ofastにはリスクが伴うことに注意してください。例えば整数と配列のオーバーフローを黙って無視し、意味のない結果を生成するため、これを使用する場合は、プログラムでオーバーフローが発生しないことを保証する必要があります。