双精度数据类型上的简单数学运算比浮点数据类型上更快

本文关键字:数据类型 简单 双精度 运算 | 更新日期: 2023-09-27 17:50:50

可能重复:
c中的doubles比float快吗?

我编写了一个简单的基准测试来检查在应用程序中将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);
    }

我得到了这样的结果(发布,没有调试,英特尔移动核心双核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上的操作几乎比在float上的操作快3倍。我在这里搜索"双浮动",我发现了这个:

使用的速度是浮动的两倍吗?

最好的答案集中在CPU体系结构上,但我不能同意这一点。

我怀疑是其他原因导致浮点运算性能低下,因为我的带有英特尔SSE的CPU应该能够一次乘或除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

双精度数据类型上的简单数学运算比浮点数据类型上更快

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

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

我只做了几个测试,有了这个变化,浮点运算的乘法速度提高了33%。

当然,这只是使比较"公平"的最简单方法。为了更好地了解float与doubles的实际比较,您需要生成随机float,并在各个类型的整个范围内对每个类型进行doubles,或者更好的是,这两个值都包含表示程序将使用的数据类型的值。

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指令。