在C#中获取数字部分值的最快方法是什么?

时间:2009-05-22 17:32:14

标签: c# floating-point

float f = 5.13;
double d = 5.13;

float fp = f - (float)Math.floor(f);
double dp = d - Math.floor(d);

每次调用外部函数有没有更快的方法?

6 个答案:

答案 0 :(得分:5)

“外部功能”?

System.Math内置于mscorlib!

这实际上是最快的方法。

答案 1 :(得分:3)

你可以将f转换为一个可以修剪小数部分的int。这假设你的双打属于整数范围。

当然,抖动可能足够聪明,可以将Math.floor优化为一些内联的asm,它可以比执行转换为int更快,然后再转换为浮动。

您是否实际测量并验证过Math.floor的性能是否会影响您的程序?如果还没有,那么在你知道这个问题之前,你不应该费心去做这个级别的微优化,然后根据原始代码测量这个替代方案的性能。

编辑:这看起来更快。使用Math.Floor()时,以下代码需要717ms,在发布模式下,我的机器上的int cast代码需要172 ms。但同样,我怀疑性能提升真的很重要 - 为了让这个可以测量我必须进行100米迭代。此外,我发现Math.Floor()更具可读性和显而易见性,未来的CLR可以为Math.Floor发出更优化的代码并轻松击败这种方法。

    private static double Floor1Test()
    {
        // Keep track of results in total so ops aren't optimized away.
        double total = 0;
        for (int i = 0; i < 100000000; i++)
        {
            float f = 5.13f;
            double d = 5.13;
            float fp = f - (float)Math.Floor(f);
            double dp = d - (float)Math.Floor(d);
            total = fp + dp;
        }

        return total;
    }

    private static double Floor2Test()
    {
        // Keep track of total so ops aren't optimized away.
        double total = 0;
        for (int i = 0; i < 100000000; i++)
        {
            float f = 5.13f;
            double d = 5.13;
            float fp = f - (int)(f);
            double dp = d - (int)(d);
            total = fp + dp;
        }

        return total;
    }

    static void Main(string[] args)
    {
        System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();

        // Unused run first, guarantee code is JIT'd.
        timer.Start();
        Floor1Test();
        Floor2Test();
        timer.Stop();

        timer.Reset();
        timer.Start();
        Floor1Test();
        timer.Stop();
        long floor1time = timer.ElapsedMilliseconds;

        timer.Reset();
        timer.Start();
        Floor2Test();
        timer.Stop();

        long floor2time = timer.ElapsedMilliseconds;

        Console.WriteLine("Floor 1 - {0} ms", floor1time);
        Console.WriteLine("Floor 2 - {0} ms", floor2time);
    }
}

答案 2 :(得分:3)

唐纳德·E·克努特说:

  

“我们应该忘记效率低,大约97%的时间说:过早   优化是万恶之源。“

因此,除非您对应用程序进行基准测试并发现此操作是瓶颈的正面证据,否则不要费心优化这些代码。

答案 3 :(得分:2)

嗯,我怀疑你会获得任何真实世界的性能提升,但根据Reflector Math.Floor是这样的:

public static decimal Floor(decimal d)
{
    return decimal.Floor(d);
}

可以说是

double dp = d - decimal.Floor(d);

可能会更快。 (编译器优化使我知道的整点意义不大......)


对于那些可能有兴趣将其理解为十进制的人。地板是:

public static decimal Floor(decimal d)
{
    decimal result = 0M;
    FCallFloor(ref result, d);
    return result;
}

FCallFloor是对非托管代码的调用,因此你几乎处于“优化”的极限。

答案 4 :(得分:2)

对于Decimal,我建议忽略所有人不要改变它并尝试使用Decimal.Truncate。无论它是否更快,它一个专门用于你想要做的事情的功能,因此更清晰。

哦,顺便说一句,它更快:

        System.Diagnostics.Stopwatch foo = new System.Diagnostics.Stopwatch();

        Decimal x = 1.5M;
        Decimal y = 1;
        int tests = 1000000;
        foo.Start();
        for (int z = 0; z < tests; ++z)
        {
            y = x - Decimal.Truncate(x);
        }
        foo.Stop();
        Console.WriteLine(foo.ElapsedMilliseconds);

        foo.Reset();
        foo.Start();
        for (int z = 0; z < tests; ++z)
        {
            y = x - Math.Floor(x);
        }
        foo.Stop();
        Console.WriteLine(foo.ElapsedMilliseconds);
        Console.ReadKey();

//Output: 123
//Output: 164

编辑:修正了我的解释和代码。

答案 5 :(得分:0)

它是静态的,所以这应该非常快,没有任何对象可以站起来。您可以随时进行数学水平计算,但除非您有一些认真使用该功能。可能floor()方法已经这样做了,但如果你需要一些非常快的东西,你可以内联它并删除支票等,但在C#中这不是你最大的性能问题。