3

可能的重复:
双打比 c# 中的浮点数快吗?

我编写了简单的基准测试来检查在我的应用程序中更改double数据类型可以获得多少性能。float这是我的代码:

    // my form: 
    // one textbox: textbox1 (MultiLine property set to true)
    // one button: button1 with event button1_Click

    private void button1_Click(object sender, EventArgs e)
    {

        int num = 10000000;

        float[] floats1 = new float[num];
        float[] floats2 = new float[num];
        float[] floatsr = new float[num];  // array for results
        double[] doubles1 = new double[num];
        double[] doubles2 = new double[num];
        double[] doublesr = new double[num]; // array for results

        Stopwatch stw = new Stopwatch();

        log("Preparing data");

        Random rnd = new Random();

        stw.Start();

        for (int i = 0; i < num; i++)
        {
            floats1[i] = NextFloat(rnd);
            floats2[i] = NextFloat(rnd);
            doubles1[i] = rnd.NextDouble();
            doubles2[i] = rnd.NextDouble();
        }
        stw.Stop();
        log(stw.Elapsed.TotalMilliseconds.ToString()+"ms");
        stw.Reset();




        log("");


        stw.Start();
        for (int i = 0; i <# i++)
        {
            floatsr[i] = floats1[i] * floats2[i];
        }
        stw.Stop();
        log("Multiplying floats: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
        stw.Reset();



        stw.Start();
        for (int i = 0; i < num; i++)
        {
            doublesr[i] = doubles1[i] * doubles2[i];
        }
        stw.Stop();
        log("Multiplying doubles: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
        stw.Reset();


        stw.Start();
        for (int i = 0; i < num; i++)
        {
            floatsr[i] = floats1[i] / floats2[i];
        }
        stw.Stop();
        log("Dividing floats: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
        stw.Reset();


        stw.Start();
        for (int i = 0; i < num; i++)
        {
            doublesr[i] = doubles1[i] / doubles2[i];
        }
        stw.Stop();
        log("Dividing doubles: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
        stw.Reset();

    }

    private void log(string text)
    {
        textBox1.Text = textBox1.Text + text + Environment.NewLine;
    }

    // I found that function somewhere on stackoverflow
    static float NextFloat(Random random)
    {
        double mantissa = (random.NextDouble() * 2.0) - 1.0;
        double exponent = Math.Pow(2.0, random.Next(-126, 128));
        return (float)(mantissa * exponent);
    }

我得到了这样的结果(发布,无调试,Intel Mobile Core Duo T2500 2.0GHz 2MB CPU):

Preparing data 5275,6862ms

Multiplying floats: 442,7865ms 
Multiplying doubles: 169,4028ms
Dividing floats: 550,7052ms 
Dividing doubles: 164,1607ms

我很惊讶,对 . 的操作double几乎比对 . 的操作快 3 倍float。我在这里搜索“双浮动”,我发现了这个:

使用 double 比 float 快吗?

最佳答案集中在 CPU 架构上,但我不同意。

我怀疑是其他原因导致浮点数性能低下,因为我的 CPU 与英特尔 SSE 应该能够一次乘法或除法 4 个浮点数(打包浮点指令),或者一次 2 个双精度数。所以浮动应该更快。

也许编译器(或 .net 中的 clr)正在以某种方式优化内存使用?

有什么办法可以优化它并使浮动更快?

请不要重复报告,我看到了其他问题,但他们并不满意。


更改生成浮点数的方法后的结果现在看起来很好(Servy 建议):

Preparing data 1367,0678ms

Multiplying floats: 109,8742ms 
Multiplying doubles: 149,9555ms
Dividing floats: 167,0079ms 
Dividing doubles: 168,6821ms
4

2 回答 2

6

它与您如何生成随机数有关。浮点数的乘除并不完全相同;这些数字的实际值很重要。在浮点数的情况下,您要在相当大的范围内填充一个值。如果你创建你的浮点数,使它们在 0 和 1 之间,就像双打一样,那么它会更像你所期望的那样。只需更改NextFloat为:

static float NextFloat(Random random)
{
    return (float) random.NextDouble();
}

我刚刚进行了一些测试,通过这种更改,浮点数的乘法速度提高了 33%。

当然,这只是使比较“公平”的最简单方法。为了更好地了解浮点数与双精度浮点数的真正比较,您需要在各个类型的全部范围内生成随机浮点数和双精度数,或者更好的是,两者都保存代表程序将使用的数据类型的值。

于 2013-01-04T14:36:42.943 回答
4

在某些情况下,浮点数上的 GPU 操作仍然更快,因为它们具有 32 位浮点硬件。

您的 x86(或 x86_64)架构 CPU 在数学协处理器中不支持 32 位。甚至 64 位支持。x87 浮点单元使用 80 位算术。

现在,现代 x86 CPU 确实具有 SIMD 指令(MMX、SSE、AVX),硬件支持 32 位和 64 位浮点运算,性能更高——如果您可以在 SIMD 单元中完成所有操作。在 SIMD 和 FPU 之间移动数据会降低性能。

从当前版本开始,.NET 不使用 MMX 或 SSE 或 AVX。您可以尝试 Mono,它提供了 JIT 编译为 SIMD 指令的内在方法。或者您可以将本机代码用于对性能最敏感的部分,因为现代 C++ 编译器不仅允许使用 SIMD,而且可以将看起来普通的代码自动向量化为 SIMD 指令。

于 2013-01-04T14:35:29.863 回答