【发布时间】:2018-09-03 22:00:25
【问题描述】:
这是我提出的一种计算平方根的算法,目前在使用循环 n 次和秒表测试它时,它比 C# Math.Sqrt() 慢大约 20-100 倍;
有没有什么方法可以提高这个函数的性能,或者性能是否和这个特定算法一样好?
我的 C# 平方根算法:
static class MyMath
{
public static double Sqrt(double _d)
{
double x = 0;
double y = 2;
double z = 1;
double w = _d;
double h = 1;
double t = 0;
double px = 0;
int itr = 0;
while (true)
{
w = (w / y);
h *= y;
if (h > w)
{
t = w;
w = h;
h = t;
z *= 0.5;
y = (1 + z);
}
x = ((w + h) * 0.5);
if (itr >= 100 || w == h || px == x)
{
return (x);
}
px = x;
itr++;
}
}
}
我如何测试性能:
using System.Diagnostics;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000; i++)
{
MyMath.Sqrt(2);
}
sw.Stop();
Debug.Print(sw.ElapsedTicks.ToString());
EDIT3:略微改进的版本:
static class MyMath
{
public static double Sqrt(double _d)
{
double x = 0;
double y = 2;
double z = 1;
double w = _d;
double h = 1;
double t = 0;
double px = 1;
while (true)
{
if (x == px)
{
return ((w + h) * 0.5);
}
if (w < h)
{
t = w;
w = h;
h = t;
z *= 0.25;
y = (z + 1);
px = x;
}
w /= y;
h *= y;
x = (w + h);
}
}
}
EDIT3:更新了略微改进的版本2 + 更改了基准方法2: (在发布模式下运行)
Stopwatch sw = new Stopwatch();
int n = 100000;
double[] squareArr = new double[n];
Random rng = new Random(1234);
for (int i = 0; i < n; i++)
{
squareArr[i] = rng.Next(1, 100000);
}
sw.Start();
for (int i = 0; i < n; i++)
{
squareArr[i] = MyMath.Sqrt(squareArr[i]) ;
}
sw.Stop();
debugBox.AppendText("AverageTime: " + (sw.ElapsedTicks / (double)n).ToString());
目前根据我的测试默认 Math.Sqrt() ~0.086 Ticks 和 mySqrt() ~4.8 Ticks。
编辑 4:(修复错误:在 if 语句中移动了 px = x)
【问题讨论】:
-
那么为什么不使用
Math.Sqrt呢?你为什么要重新发明轮子?如果有更快的方法,Math.Sqrt会这样做... -
这个问题更适合codereview.stackexchange.com
-
Math.Sqrt在内部用原生 C++ 实现,比 C# 性能要好得多,而且比你想象的要优化得多。 -
mySqrt(12544).ToString("G17") == 111.99999999999999。不要被默认的四舍五入的字符串表示所迷惑。 -
您的方法比 Math.Sqrt 慢得多,这是意料之中的。在现代 PC 上,sqrt 花费的时间与单个部门大致相同,例如在 Intel Haswell 上,FDIV 指令需要 10-24 个周期,FSQRT 指令需要 10-23 个周期。还有另一个浮点除法指令 divpd,但它只是稍微快一点,10-20 个周期。 agner.org/optimize/instruction_tables.pdf 你的循环中有很多部门。
标签: c# algorithm performance