简体   繁体   English

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

[英]What's the fastest way to get the partial value of a number in C#?

float f = 5.13;
double d = 5.13;

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

Isn't there any faster way than calling an external function every time? 有没有比每次调用外部函数更快的方法?

"External function"? “外部功能”?

System.Math is built into mscorlib! System.Math内置于mscorlib中!

This is actually the fastest way to do this. 这实际上是最快的方法。

You could cast f to an int which would trim the fractional part. 您可以将f转换为int,这将修剪小数部分。 This presumes that your doubles fall within the range of an integer. 这假设您的双打属于整数范围。

Of course, the jitter may be smart enough to optimize Math.floor to some inlined asm that'll do the floor, which may be faster than the cast to int then cast back to float. 当然,抖动可能足够聪明,可以将Math.floor优化为一些内联的asm,它可以比执行转换更快,然后转换为浮动。

Have you actually measured and verified that the performance of Math.floor is affecting your program? 您是否真的已经测量并验证了Math.floor的性能是否会影响您的程序? If you haven't, you shouldn't bother with this level of micro-optimization until you know that is a problem, and then measure the performance of this alternative against the original code. 如果还没有,在你知道这是一个问题之前,你不应该为这个级别的微优化而烦恼,然后根据原始代码测量这个替代方案的性能。

EDIT: This does appear faster. 编辑:这看起来更快。 The following code takes 717ms when using Math.Floor(), and 172 ms for the int casting code on my machine, in release mode. 使用Math.Floor()时,以下代码需要717ms,在发布模式下,我的机器上的int cast代码需要172 ms。 But again, I doubt the perf improvement really matters - to get this to be measurable I had to do 100m iterations. 但同样,我怀疑性能提升真的很重要 - 为了让这个可以测量我必须进行100米迭代。 Also, I find Math.Floor() to be much more readable and obvious what the intent is, and a future CLR could emit more optimal code for Math.Floor and beat out this approach easily. 此外,我发现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);
    }
}

Donald E. Knuth said: Donald E. Knuth说:

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." “我们应该忘记小的效率,比如大约97%的时间:过早的优化是所有邪恶的根源。”

So unless you have benchmarked your application and found positive evidence that this operations is the bottleneck, then don't bother optimizing these this line of code. 因此,除非您对应用程序进行基准测试并发现此操作是瓶颈的正面证据,否则不要费心优化这些代码。

Well, I doubt you'll get any real world performance gain, but according to Reflector Math.Floor is this: 嗯,我怀疑你会获得任何真实的世界性能增益,但根据Reflector Math.Floor是这样的:

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

So arguably 所以可以说

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

may be quicker. 可能会更快。 (Compiler optimisations make the whole point moot I know...) (编译器优化使我知道的整点意义不大......)


For those who may be interested to take this to its logical conclusion decimal.Floor is: 对于那些可能有兴趣将其带入其逻辑结论十进制的人。地板是:

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

with FCallFloor being a invoke to unmanaged code, so you are pretty much at the limit of the "optimisation" there. FCallFloor是对非托管代码的调用,因此您几乎处于“优化”的极限。

In the case of Decimal , I would recommend ignoring everyone yelling not to change it and try using Decimal.Truncate . Decimal的情况下,我建议忽略大家不要改变它并尝试使用Decimal.Truncate Whether it is faster or not, it is a function specifically intended for what you are trying to do and thus is a bit clearer. 无论是否更快,它都是专门针对您要做的事情的功能,因此更清晰一点。

Oh, and by the way, it is faster: 哦,顺便说一句,它更快:

        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

Edit: Fixed my explanation and code. 编辑:修正了我的解释和代码。

It is static so this should be really fast, there is no object to stand up. 它是静态的,所以这应该非常快,没有任何目标可以站起来。 You can always to bit level math, but unless you have some serious use the function. 您可以随时进行数学水平计算,但除非您有一些认真使用该功能。 Likely the floor() method is already doing this, but you could inline it and cut out checks etc if you need something really fast, but in C# this is not your greatest performance issue. 可能floor()方法已经这样做了,但如果你需要非常快的东西,你可以内联它并删除支票等,但在C#中这不是你最大的性能问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM