我尝试优化某些计算过程的性能。 像下面这样的计算浪费了大量时间:
class Program
{
static void Main(string[] args)
{
var arrLength = 1000000;
var arr1 = GetArrayOf_A(arrLength);
var arr2 = GetArrayOf_B(arrLength);
var arr3 = GetArrayOf_C(arrLength);
var result1 = new bool[arrLength];
var result2 = new bool[arrLength];
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < arrLength; i++)
{
result1[i] = Math.Abs((long) (arr1[i] * 1e6) / 1e6D)
>
(long) ((arr2[i] + arr3[i]) * 1e6) / 1e6D;
}
sw.Stop();
var t1 = sw.Elapsed.TotalMilliseconds;
sw.Restart();
for (var i = 0; i < arrLength; i++)
{
//result2[i] = Math.Round(Math.Abs(arr1[i]) - (arr2[i] + arr3[i]),6) > 0; // Incorrect, example by index = 0
//result2[i] = Math.Abs(arr1[i]) - (arr2[i] + arr3[i]) > 0.000001; // Incorrect, example by index = 1
//result2[i] = Math.Abs(arr1[i]) - (arr2[i] + arr3[i]) > 0.0000001; // Incorrect, example by index = 2
result2[i] = Math.Abs(arr1[i]) - (arr2[i] + arr3[i]) > 0.00000001; // Incorrect, example by index = 3
}
sw.Stop();
var t2 = sw.Elapsed.TotalMilliseconds;
var areEquivalent = true;
for (var i = 0; i < arrLength; i++)
{
if (result1[i] == result2[i]) continue;
areEquivalent = false;
break;
}
Console.WriteLine($"Functions are equivalent : {areEquivalent}");
if (areEquivalent)
{
Console.WriteLine($"Current function total time: {t1}ms");
Console.WriteLine($"Equivalent function total time: {t2}ms");
}
Console.WriteLine("Press ANY key to quit . . .");
Console.ReadKey();
}
private static readonly Random _rand = new Random(DateTime.Now.Millisecond);
private const int NumberOfRepresentativeExamples = 4;
private static double[] GetArrayOf_A(int arrLength)
{
if(arrLength<=NumberOfRepresentativeExamples)
throw new ArgumentException($"{nameof(arrLength)} should be bigger than {NumberOfRepresentativeExamples}");
var arr = new double[arrLength];
// Representative numbers
arr[0] = 2.4486382579120365;
arr[1] = -1.1716818990000011;
arr[2] = 5.996414627393257;
arr[3] = 6.0740085822069;
// the rest is to build time statistics
FillTheRestOfArray(arr);
return arr;
}
private static double[] GetArrayOf_B(int arrLength)
{
if(arrLength<=NumberOfRepresentativeExamples)
throw new ArgumentException($"{nameof(arrLength)} should be bigger than {NumberOfRepresentativeExamples}");
var arr = new double[arrLength];
// Representative numbers
arr[0] = 2.057823225;
arr[1] = 0;
arr[2] = 2.057823225;
arr[3] = 2.060649901;
// the rest is to build time statistics
FillTheRestOfArray(arr);
return arr;
}
private static double[] GetArrayOf_C(int arrLength)
{
if(arrLength<=NumberOfRepresentativeExamples)
throw new ArgumentException($"{nameof(arrLength)} should be bigger than {NumberOfRepresentativeExamples}");
var arr = new double[arrLength];
// Representative numbers
arr[0] = 0.3908145999796302;
arr[1] = 1.1716809269999997;
arr[2] = 3.9385910820740282;
arr[3] = 4.0133582670728858;
// the rest is to build time statistics
FillTheRestOfArray(arr);
return arr;
}
private static void FillTheRestOfArray(double[] arr)
{
for (var i = NumberOfRepresentativeExamples; i < arr.Length; i++)
{
arr[i] = _rand.Next(0, 10) + _rand.NextDouble();
}
}
}
其中“ a”,“ b”和“ c”为双精度,“ b”和“ c”为正,“ a”可能为负。
isBigger仅在“ a”的绝对值大于“ b + c”而不考虑小数点后第六位的任何情况下才为真。
所以我看一下这个表达式,我理解它的作用,但是对我来说似乎效率很低,因为它会将比较数字乘以百万并除以仅仅得到小数点后6位。
下面是我用来尝试创建更好解决方案的程序。到目前为止,我失败了。 有人可以帮我吗?
{{1}}
答案 0 :(得分:1)
您不需要除法,因为如果(x/100) < (y/100)
表示x<y
。
for(var i = 0; i < arrLength; i++)
{
result2[i] = Math.Abs((long)(arr1[i] * 1e6))
> (long)((arr2[i] + arr3[i]) * 1e6);
}
显示给我的结果
Arrays have 1000000 elements.
Functions are equivalent : True
Current function total time: 40.10ms 24.94 kflop
Equivalent function total time: 22.42ms 44.60 kflop
A speedup of 78.83 %
PS。确保比较包含数学优化功能的二进制文件的 RELEASE 版本。
PS2。显示代码是
Console.WriteLine($"Arrays have {arrLength} elements.");
Console.WriteLine($"Functions are equivalent : {areEquivalent}");
Console.WriteLine($" Current function total time: {t1:F2}ms {arrLength/t1/1e3:F2} kflop");
Console.WriteLine($"Equivalent function total time: {t2:F2}ms {arrLength/t2/1e3:F2} kflop");
Console.WriteLine($"An speedup of {t1/t2-1:P2}");
答案 1 :(得分:1)
总体而言,您的问题属于实时编程领域。不一定是实时约束,但它会进入相同的优化范围。最后一纳秒的时间被刮掉的类型。
.NET不是这种操作的理想方案。通常,这件事是在专用的挂绳上完成的。接下来的最好的事情是在Assembler,C或本机C ++中执行此操作。 .NET具有其他功能,例如垃圾收集器和即时编译器,这些功能甚至使获取可靠的基准测试结果也变得棘手。可靠的运行时性能要差得多。
对于数据类型,Float应该是最快的操作。由于历史原因,对浮动操作进行了优化。
您的评论中有一项提到物理,并且确实有一个数组。我看到诸如array[i] = array2[i] + array3[i]
之类的东西。因此,也许这应该是您在GPU上运行的矩阵运算?这种“巨大的并行阵列阵列选择”正是GPU擅长的。
除非您告诉我们您在进行sa操作时实际上在做什么,否则这就是我能给出的最佳答案。
答案 2 :(得分:0)
这是您要找的吗?
Math.Abs(a) - (b + c) > 0.000001
或者您是否想知道差异是否更大(两种方式之间的差异):
Math.Abs(Math.Abs(a) - (b + c)) > 0.000001
(我假设您不是因为速度而限制此精度,而是因为固有的浮点数限制精度。)
答案 3 :(得分:0)
除了在此站点上问这个问题外,我还问了我的一个好朋友,到目前为止,他提供了最佳答案。在这里:
result2[i] = Math.Abs(arr1[i]) - (arr2[i] + arr3[i]) > 0.000001 ||
Math.Abs((long)(arr1[i] * 1e6)) > (long)((arr2[i] + arr3[i])*1e6);
我很高兴有这样的朋友:)