Luk*_*don 9 .net c# c++ f# stopwatch
由于F#2.0已经成为VS2010的一部分,我对F#感兴趣.我想知道使用它有什么意义.我读了一下,我做了一个测量函数调用的基准.我用过Ackermann的函数:)
C#
sealed class Program
{
public static int ackermann(int m, int n)
{
if (m == 0)
return n + 1;
if (m > 0 && n == 0)
{
return ackermann(m - 1, 1);
}
if (m > 0 && n > 0)
{
return ackermann(m - 1, ackermann(m, n - 1));
}
return 0;
}
static void Main(string[] args)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
Console.WriteLine("C# ackermann(3,10) = " + Program.ackermann(3, 10));
stopWatch.Stop();
Console.WriteLine("Time required for execution: " + stopWatch.ElapsedMilliseconds + "ms");
Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud)
C++
class Program{
public:
static inline int ackermann(int m, int n)
{
if(m == 0)
return n + 1;
if (m > 0 && n == 0)
{
return ackermann(m - 1, 1);
}
if (m > 0 && n > 0)
{
return ackermann(m - 1, ackermann(m, n - 1));
}
return 0;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
clock_t start, end;
start = clock();
std::cout << "CPP: ackermann(3,10) = " << Program::ackermann(3, 10) << std::endl;
end = clock();
std::cout << "Time required for execution: " << (end-start) << " ms." << "\n\n";
int i;
std::cin >> i;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
F#
// Ackermann
let rec ackermann m n =
if m = 0 then n + 1
elif m > 0 && n = 0 then ackermann (m - 1) 1
elif m > 0 && n > 0 then ackermann (m - 1) (ackermann m (n - 1))
else 0
open System.Diagnostics;
let stopWatch = Stopwatch.StartNew()
let x = ackermann 3 10
stopWatch.Stop();
printfn "F# ackermann(3,10) = %d" x
printfn "Time required for execution: %f" stopWatch.Elapsed.TotalMilliseconds
Run Code Online (Sandbox Code Playgroud)
Java的
public class Main
{
public static int ackermann(int m, int n)
{
if (m==0)
return n + 1;
if (m>0 && n==0)
{
return ackermann(m - 1,1);
}
if (m>0 && n>0)
{
return ackermann(m - 1,ackermann(m,n - 1));
}
return 0;
}
public static void main(String[] args)
{
System.out.println(Main.ackermann(3,10));
}
}
Run Code Online (Sandbox Code Playgroud)
那么
C#= 510ms
c ++
= 130ms F#= 185ms
Java = Stackoverflow :)
它是F#的强大功能(除了少量代码)如果我们想使用.Net并获得更快的执行速度?我可以优化任何这些代码(尤其是F#)吗?
更新.我摆脱了Console.WriteLine并在没有调试器的情况下运行C#代码:C#= 400ms
Tom*_*cek 14
我相信在这种情况下,C#和F#之间的区别归功于尾部调用优化.
尾部调用是指您在函数中作为"最后一件事"完成的递归调用.在这种情况下,F#实际上并不生成调用指令,而是将代码编译成循环(因为调用是"最后一件事",我们可以重用当前的堆栈帧并跳转到方法的开头) .
在您的实现中ackermann,两个调用是尾调用,而其中只有一个不是(结果作为参数传递给另一个ackermann调用的那个).这意味着F#版本实际上不经常调用"调用"指令(很多?).
通常,性能配置文件与C#的性能配置文件大致相同.这里有很多与F#和C#性能相关的帖子:
这是一种调用相关的函数,因为它是减少函数调用的常用方法.
您可以通过memoization(缓存)使这种类型的递归函数更快.您也可以在C#中执行此操作(示例.)我有18ms.
open System.Collections.Generic
let memoize2 f =
let cache = Dictionary<_, _>()
fun x y ->
if cache.ContainsKey (x, y) then
cache.[(x, y)]
else
let res = f x y
cache.[(x, y)] <- res
res
// Ackermann
let rec ackermann =
memoize2 (fun m n ->
if m = 0 then n + 1
elif m > 0 && n = 0 then ackermann (m - 1) 1
elif m > 0 && n > 0 then ackermann (m - 1) (ackermann m (n - 1))
else 0
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2889 次 |
| 最近记录: |