The fastest way to determine if a double is finite?

What is the fastest way to determine if a double value is the final value (neither NaN nor positive / negative infinity) in IL without throwing an exception?

I considered the following approaches (C # notation is for reader convenience only, in my project I use IL for this):

  • !double.IsNaN(x) && !double.IsInfinity(x) is the most obvious and probably the slowest, since 2 method calls are involved.

  • (*(((long*) &x)) & 0x7fffffffffffffffL) < 0x7ff0000000000000L

or in IL:

  ldloca x conv.u ldind.i8 ldc.i8 0x7fffffffffffffff and ldc.i8 0x7ff0000000000000 clt 

My questions about the second approach:

  • According to my research, this should pinpoint whether any given x finite. It's true?

  • Is this the best way (in terms of performance) to solve a problem in IL, or is there a better (faster) solution?

PS I really appreciate the recommendations for running my own tests and finding out, and I certainly will. Just thought, maybe someone already had a similar problem and he knows the answer. PPS Yes, I understand that here we are talking about nanoseconds, and yes, they are important for my particular case.

+6
source share
2 answers

Microsoft uses this :

 public unsafe static bool IsNaN(double d) { return (*(UInt64*)(&d) & 0x7FFFFFFFFFFFFFFFL) > 0x7FF0000000000000L; } 

And this :

 public unsafe static bool IsInfinity(double d) { return (*(long*)(&d) & 0x7FFFFFFFFFFFFFFF) == 0x7FF0000000000000; } 

If using !double.IsNaN(x) && !double.IsInfinity(x) is the real bottleneck of your program, which I doubt, I recommend you use these functions, it will be easier to read and maintain.

+10
source

Without unsafe context and mixing NaN , + Inf , -Inf :

 var isFinite = ((BitConverter.DoubleToInt64Bits(d) >> 52) & 0x7ff) != 0x7ff; 

Explanation:

The double value is 64 bits, which is stored as:

  • 1 bit for sign
  • 11 bit for exhibitor
  • 52 bits for mantissa
  Bit No: 63 62 ~~~~~~~ 52 51 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~ 0
 Bit: 0 00000000000 0000000000000000000000000000000000000000000000000000
        sign exponent mantissa

 If sign = 0 && exponent == 11111111111 && mantissa == 0 => + Infinity
 If sign = 1 && exponent == 11111111111 && mantissa == 0 => -Infinity
 If exponent == 11111111111 && mantissa! = 0 => NaN
 If exponent! = 11111111111 => Finite

 In other terms:
 If exponent == 11111111111 => Not finite
 If exponent! = 11111111111 => Finite

 Step 1: Convert double as Int64 bits (DoubleToInt64Bits)
 Step 2: Shift right 52 bits to remove mantissa (>> 52)
 Step 3: Mask exponent bits to remove sign (& 0x7ff)
 Step 4: Check if all remaining bits are set to 1

 Note: 0b11111111111 = 0x7ff = 2047

Finally, this can be simplified to :

 var isFinite = (BitConverter.DoubleToInt64Bits(d) & 0x7ff0000000000000) != 0x7ff0000000000000; 

In extension method and unsafe :

 internal static class ExtensionMethods { public static unsafe bool IsFinite(this double d) => (*(long*)&d & 0x7ff0000000000000) != 0x7ff0000000000000; } 

Test

 Console.WriteLine("NegativeInfinity is " + (double.NegativeInfinity.IsFinite() ? "finite" : "not finite")); Console.WriteLine("PositiveInfinity is " + (double.PositiveInfinity.IsFinite() ? "finite" : "not finite")); Console.WriteLine("NaN is " + (double.NaN.IsFinite() ? "finite" : "not finite")); Console.WriteLine("Epsilon is " + (double.Epsilon.IsFinite() ? "finite" : "not finite")); Console.WriteLine("MinValue is " + (double.MinValue.IsFinite() ? "finite" : "not finite")); Console.WriteLine("MaxValue is " + (double.MaxValue.IsFinite() ? "finite" : "not finite")); 

Result

  NegativeInfinity is not finite
 PositiveInfinity is not finite
 NaN is not finite
 Epsilon is finite
 MinValue is finite
 MaxValue is finite
+1
source

Source: https://habr.com/ru/post/989331/


All Articles