我在Swift中实现了xorshift算法,只是发现Swift版本比Delphi慢大约80倍。
Xorshift描述于http://en.wikipedia.org/wiki/Xorshift
SWIFT版本:
// xcrun -sdk macosx10.10 swiftc main.swift
import Foundation
func xor_shift(x0: UInt32, y0: UInt32, z0: UInt32, w0: UInt32) -> () -> UInt32 {
var x = x0
var y = y0
var z = z0
var w = w0
func num() -> UInt32 {
let t = x ^ (x << 11)
x = y
y = z
z = w
w = w ^ (w >> 19) ^ (t ^ (t >> 8))
return w
}
return num
}
let loopcount = Int32.max
let xrand = xor_shift(2014, 12, 29, 2015)
let t0 = NSDate()
for _ in 0..<loopcount {
xrand()
}
let t1 = NSDate()
let ms = Int(t1.timeIntervalSinceDate(t0) * 1000)
println("[SWIFT] Time used: \(ms) millisecons, Loop count: \(loopcount)")
Delphi / Pascal版本:
// Command line compile:
// dcc64 xortest.dpr
{$APPTYPE CONSOLE}
program xortest;
uses sysutils;
type
TRandSeed = record
x,y,z,w: UInt32;
end;
function xrand(var seed: TRandSeed): UInt32;
var
t: UInt32;
begin
t := seed.x xor (seed.x shl 11);
seed.x := seed.y; seed.y := seed.z; seed.z := seed.w;
seed.w := seed.w xor (seed.w shr 19) xor (t xor (t shr 8));
result := seed.w
end;
var
r: TRandSeed;
t0, t1: TDateTime;
s: string;
i, loopcount: integer;
begin
// Set the rand seed
r.x := 2014; r.y := 12; r.z := 29; r.w := 2015;
loopcount := high(Int32);
t0 := now;
for i := 1 to loopcount do xrand(r);
t1 := now;
s := Format('[PASCAL] Time used: %d milliseconds, Loopcount = %d', [Trunc((t1-t0)*24*3600*1000), loopcount]);
writeln(s);
end.
测试环境:
OS X:iMac 27“retina 4 GHz Intel Core i7
Windows 7在上述iMac上的VMWare融合中运行
Swift版本输出: [SWIFT]使用时间:412568毫秒,循环次数:2147483647
Pascal版本输出: [PASCAL]使用时间:5083毫秒,Loopcount = 2147483647
Pascal版本运行速度比Swift版本快81倍,更不用说前者在虚拟机内运行了。 Apple是否在谈论Swift的快速性能,或者我的代码有什么问题吗?
答案 0 :(得分:9)
编辑:哎呀,抱歉,我错误翻译了Delphi代码的一部分,所以不如常量计算好 - 但是封闭肯定是问题所以你应该重新对它进行比较,因为它会产生显着的差异
你的Swift代码不是你的Delphi代码的直接翻译,所以你不是在比较苹果和苹果。在Swift版本中,您正在调用一个函数,该函数返回一个捕获一些变量的闭包,然后调用该闭包。而在Delphi版本中,您只是调用一个带结构的函数。下面是Delphi代码的更直接的Swift转换。
闭包通常会成为编译器优化的障碍。删除这个障碍似乎对代码有很大的帮助,因为如果我在用-O
编译后运行我的Swift等价物,它会在 0毫秒 5,341毫秒内计算2,147,483,647次xrand
次运行,与可怕的古老笔记本电脑上的封闭版本相比,238,762毫秒。
为什么呢?因为没有优化的障碍,编译器有更多的自由度来尽可能快地重写代码。 可能甚至用一个常量值替换整个函数(它也可能检测到该值甚至没有被使用,因此根本不运行该函数,这就是为什么我添加了一个存储结果和结果的打印输出,以确保)。
import Foundation
struct TRandSeed {
var x: UInt32
var y: UInt32
var z: UInt32
var w: UInt32
}
func xrand(inout seed: TRandSeed) -> UInt32{
var t = seed.x ^ (seed.x << 11)
seed.x = seed.y
seed.y = seed.z
seed.z = seed.w
seed.w = seed.w ^ (seed.w >> 19) ^ (t ^ (t >> 8))
return seed.w
}
var r = TRandSeed(x: 2014, y: 12, z: 29, w: 2015)
let loopcount = Int32.max-1
let t0 = NSDate()
for _ in 0..<loopcount {
xrand(&r)
}
let result = xrand(&r)
let t1 = NSDate()
let ms = Int(t1.timeIntervalSinceDate(t0) * 1000)
println("[SWIFT] Time used: \(ms) millisecons to calculate \(result), Loop count: \(loopcount+1)")
答案 1 :(得分:0)
我稍微修改了Airspeed Velocity的代码:
import Foundation
struct TRandSeed {
var x: UInt32
var y: UInt32
var z: UInt32
var w: UInt32
}
func xrand(inout seed: TRandSeed) -> UInt32{
let t = seed.x ^ (seed.x << 11)
seed.x = seed.y
seed.y = seed.z
seed.z = seed.w
seed.w = seed.w ^ (seed.w >> 19) ^ (t ^ (t >> 8))
return seed.w
}
var r = TRandSeed(x: 2014, y: 12, z: 29, w: 2015)
let loopcount = Int32.max
let t0 = NSDate()
var total: UInt64 = 0
for _ in 0..<loopcount {
let t = xrand(&r)
total = total &+ UInt64(t)
}
let t1 = NSDate()
let ms = Int(t1.timeIntervalSinceDate(t0) * 1000)
println("[SWIFT] Time used: \(ms) milliseconds to calculate, Loop count: \(loopcount), Total = \(total)")
我使用命令行编译它:xcrun -sdk macosx10.10 swiftc -O main.swift
新代码输出:[SWIFT]使用时间:2838毫秒计算,循环次数:2147483647,总计= 4611723097222874280
现在表现达到标准杆。 (由于Pascal版本在虚拟机内部运行,因此Swift二进制文件速度提高两倍是不公平的。)