c# - 浮点 Div/Mul > 比 Add/Sub 慢 30 倍?

标签 c# c++ performance floating-point

我最近读了这篇文章:Floating point vs integer calculations on modern hardware并且很好奇我自己的处理器在这个准基准测试中的性能,所以我将两个版本的代码放在一起,一个用 C# 编写,一个用 C++ (Visual Studio 2010 Express) 编写,并对它们进行优化编译,看看有什么问题出去。我的 C# 版本的输出相当合理:

int add/sub: 350ms
int div/mul: 3469ms
float add/sub: 1007ms
float div/mul: 67493ms
double add/sub: 1914ms
double div/mul: 2766ms

当我编译并运行 C++ 版本时,出现了一些完全不同的东西:

int add/sub: 210.653ms
int div/mul: 2946.58ms
float add/sub: 3022.58ms
float div/mul: 172931ms
double add/sub: 1007.63ms
double div/mul: 74171.9ms

我预计会有一些性能差异,但没有这么大!我不明白为什么 C++ 中的除法/乘法比加法/减法慢得多,其中托管 C# 版本对我的期望更合理。该函数的C++版本代码如下:

template< typename T> void GenericTest(const char *typestring)
{
    T v = 0;
    T v0 = (T)((rand() % 256) / 16) + 1;
    T v1 = (T)((rand() % 256) / 16) + 1;
    T v2 = (T)((rand() % 256) / 16) + 1;
    T v3 = (T)((rand() % 256) / 16) + 1;
    T v4 = (T)((rand() % 256) / 16) + 1;
    T v5 = (T)((rand() % 256) / 16) + 1;
    T v6 = (T)((rand() % 256) / 16) + 1;
    T v7 = (T)((rand() % 256) / 16) + 1;
    T v8 = (T)((rand() % 256) / 16) + 1;
    T v9 = (T)((rand() % 256) / 16) + 1;

    HTimer tmr = HTimer();
    tmr.Start();
    for (int i = 0 ; i < 100000000 ; ++i)
    {
        v += v0;
        v -= v1;
        v += v2;
        v -= v3;
        v += v4;
        v -= v5;
        v += v6;
        v -= v7;
        v += v8;
        v -= v9;
    }
    tmr.Stop();

      // I removed the bracketed values from the table above, they just make the compiler
      // assume I am using the value for something do it doesn't optimize it out.
    cout << typestring << " add/sub: " << tmr.Elapsed() * 1000 << "ms [" << (int)v << "]" << endl;

    tmr.Start();
    for (int i = 0 ; i < 100000000 ; ++i)
    {
        v /= v0;
        v *= v1;
        v /= v2;
        v *= v3;
        v /= v4;
        v *= v5;
        v /= v6;
        v *= v7;
        v /= v8;
        v *= v9;
    }
    tmr.Stop();

    cout << typestring << " div/mul: " << tmr.Elapsed() * 1000 << "ms [" << (int)v << "]" << endl;
}

C# 测试的代码不是通用的,因此实现:

static double DoubleTest()
{
    Random rnd = new Random();
    Stopwatch sw = new Stopwatch();

    double v = 0;
    double v0 = (double)rnd.Next(1, int.MaxValue);
    double v1 = (double)rnd.Next(1, int.MaxValue);
    double v2 = (double)rnd.Next(1, int.MaxValue);
    double v3 = (double)rnd.Next(1, int.MaxValue);
    double v4 = (double)rnd.Next(1, int.MaxValue);
    double v5 = (double)rnd.Next(1, int.MaxValue);
    double v6 = (double)rnd.Next(1, int.MaxValue);
    double v7 = (double)rnd.Next(1, int.MaxValue);
    double v8 = (double)rnd.Next(1, int.MaxValue);
    double v9 = (double)rnd.Next(1, int.MaxValue);

    sw.Start();
    for (int i = 0; i < 100000000; i++)
    {
        v += v0;
        v -= v1;
        v += v2;
        v -= v3;
        v += v4;
        v -= v5;
        v += v6;
        v -= v7;
        v += v8;
        v -= v9;
    }
    sw.Stop();

    Console.WriteLine("double add/sub: {0}", sw.ElapsedMilliseconds);
    sw.Reset();

    sw.Start();
    for (int i = 0; i < 100000000; i++)
    {
        v /= v0;
        v *= v1;
        v /= v2;
        v *= v3;
        v /= v4;
        v *= v5;
        v /= v6;
        v *= v7;
        v /= v8;
        v *= v9;
    }
    sw.Stop();

    Console.WriteLine("double div/mul: {0}", sw.ElapsedMilliseconds);
    sw.Reset();

    return v;
}

这里有什么想法吗?

最佳答案

对于 float div/mul 测试,您可能会得到非规范化的值,处理正常的浮点值要慢得多。这不是 int 测试的问题,并且会在稍后的 double 测试中出现。

您应该能够将其添加到 C++ 的开头以将非规范化清零:

_controlfp(_DN_FLUSH, _MCW_DN);

不过我不确定如何在 C# 中执行此操作(或者是否可能)。

这里有更多信息: Floating Point Math Execution Time

关于c# - 浮点 Div/Mul > 比 Add/Sub 慢 30 倍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3292862/

相关文章:

c# - 通过 MySql Insert 传递 Foreach 变量

c++ - HEAP 上的数组分配(单独分配与......连续分配?)

php - 大型数据库的高性能 PHP 相似性检查

java - 使用 switch/if 或嵌套三元运算符是否更快?

javascript - 比较两个对象数组,并更新第二个对象的值。非常慢

c# - C#事件系统对于单线程程序是确定性的吗?

c# - 无法使用 https 获取网络响应

c# - 对象数组的匿名类型?

c++ - MPI Allgatherv 函数出现问题

c++ - C++ 中二维数组初始化错误