Double.IsNaN test 100 times faster?

后端 未结 3 1503
无人及你
无人及你 2021-01-01 09:45

I found this in the .NET Source Code: It claims to be 100 times faster than System.Double.IsNaN. Is there a reason to not use this function instead of Sys

3条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-01 10:12

    It claims to be 100 times faster than System.Double.IsNaN

    Yes, that used to be true. You are missing the time-machine to know when this decision was made. Double.IsNaN() didn't used to look like that. From the SSCLI10 source code:

       public static bool IsNaN(double d)
       {
           // Comparisions of a NaN with another number is always false and hence both conditions will be false.
           if (d < 0d || d >= 0d) {
              return false;
           }
           return true;
       }
    

    Which performs very poorly on the FPU in 32-bit code if d is NaN. Just an aspect of the chip design, it is treated as exceptional in the micro-code. The Intel processor manuals say very little about it, other than documenting a processor perf counter that tracks the number of "Floating Point assists" and noting that the micro-code sequencer comes into play for denormals and NaNs, "potentially costing hundreds of cycles". Not otherwise an issue in 64-bit code, it uses SSE2 instructions which don't have this perf hit.

    Some code to play with to see this yourself:

    using System;
    using System.Diagnostics;
    
    class Program {
        static void Main(string[] args) {
            double d = double.NaN;
            for (int test = 0; test < 10; ++test) {
                var sw1 = Stopwatch.StartNew();
                bool result1 = false;
                for (int ix = 0; ix < 1000 * 1000; ++ix) {
                    result1 |= double.IsNaN(d);
                }
                sw1.Stop();
                var sw2 = Stopwatch.StartNew();
                bool result2 = false;
                for (int ix = 0; ix < 1000 * 1000; ++ix) {
                    result2 |= IsNaN(d);
                }
                sw2.Stop();
                Console.WriteLine("{0} - {1} x {2}%", sw1.Elapsed, sw2.Elapsed, 100 * sw2.ElapsedTicks / sw1.ElapsedTicks, result1, result2);
    
            }
            Console.ReadLine();
        }
        public static bool IsNaN(double d) {
            // Comparisions of a NaN with another number is always false and hence both conditions will be false.
            if (d < 0d || d >= 0d) {
                return false;
            }
            return true;
        }
    }
    

    Which uses the version of Double.IsNaN() that got micro-optimized. Such micro-optimizations are not evil in a framework btw, the great burden of the Microsoft .NET programmers is that they can rarely guess when their code is in the critical path of an application.

    Results on my machine when targeting 32-bit code (Haswell mobile core):

    00:00:00.0027095 - 00:00:00.2427242 x 8957%
    00:00:00.0025248 - 00:00:00.2191291 x 8678%
    00:00:00.0024344 - 00:00:00.2209950 x 9077%
    00:00:00.0024144 - 00:00:00.2321169 x 9613%
    00:00:00.0024126 - 00:00:00.2173313 x 9008%
    00:00:00.0025488 - 00:00:00.2237517 x 8778%
    00:00:00.0026940 - 00:00:00.2231146 x 8281%
    00:00:00.0025052 - 00:00:00.2145660 x 8564%
    00:00:00.0025533 - 00:00:00.2200943 x 8619%
    00:00:00.0024406 - 00:00:00.2135839 x 8751%
    

提交回复
热议问题