【发布时间】:2022-02-24 17:26:39
【问题描述】:
以下 C# 程序计算平方根的 1000 万次巴比伦迭代。
using System;
using System.Diagnostics;
namespace Performance {
public class Program {
public static void MeasureTime(long n, Action f) {
Stopwatch watch = new Stopwatch();
watch.Start();
for (long i = 0; i < n; ++i) f();
watch.Stop();
Console.WriteLine($"{(n / watch.ElapsedMilliseconds) / 1000} Mop/s, {watch.ElapsedMilliseconds} ms");
}
public static void TestSpeed(double a) {
Console.WriteLine($"Parameter {a}");
double x = a;
long n = 10_000_000;
MeasureTime(n, () => x = (a / x + x) / 2);
Console.WriteLine($"{x}\n");
}
static void Main(string[] args) {
TestSpeed(2);
TestSpeed(Double.PositiveInfinity);
}
}
}
当我在我的计算机上以发布模式运行它时,我得到:
Parameter 2
99 Mop/s, 101 ms
1,41421356237309
Parameter ∞
3 Mop/s, 3214 ms
NaN
这里的Mop/s 代表每秒百万次操作。当参数为无穷大时,由于某种原因,代码速度减慢了 30 倍以上。
这是为什么?
为了比较,这里是用 C++20 编写的相同程序:
#include <iostream>
#include <chrono>
#include <format>
namespace Performance {
template <typename F>
void MeasureTime(long long n, F f) {
auto begin = std::chrono::steady_clock::now();
for (long long i = 0; i < n; ++i) f();
auto end = std::chrono::steady_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
std::cout << std::format("{0} Mop/s, {1} ms", (n / ms) / 1000, ms) << std::endl;
}
void TestSpeed(double a) {
std::cout << std::format("Parameter {0}", a) << std::endl;
double x = a;
long long n = 10'000'000;
MeasureTime(n, [&]() { x = (a / x + x) / 2; });
std::cout << std::format("{0}\n\n", x);
}
}
using namespace Performance;
int main() {
auto inf = std::numeric_limits<double>::infinity();
TestSpeed(2);
TestSpeed(inf);
return 0;
}
当我在发布模式下运行这个程序时,我得到:
Parameter 2
181 Mop/s, 55 ms
1.414213562373095
Parameter inf
192 Mop/s, 52 ms
-nan(ind)
这是预期的;即性能没有差异。
这两个程序均在 Visual Studio 2022 版本 17.1.0 中构建。 C# 项目是一个 Net Framework 4.7.2 控制台应用程序。
【问题讨论】:
-
这仅通过调试配置重现。
-
对我来说,默认发布配置会发生这种情况。似乎有一些特定于我的环境或机器的东西,因为当我在各种在线 C# 编译器上运行它时,它运行良好。
-
在选项中有一个选项“首选 32 位”。取消选中该选项时,问题就解决了!我想知道发生了什么事。
-
fdiv和fadd用于 32 位+调试环境。他们似乎计算 NaN 数很慢。 This answer 包含一些细节。 -
另一方面,在 32 位模式下构建 C++ 程序完全不会影响其性能。
标签: c# performance floating-point