Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The fastest way to detect if a double is finite?

Tags:

c#

.net

il

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

I was considering the following approaches (c# notation for reader's convenience only, in my project I'm using IL for this):

  1. !double.IsNaN(x) && !double.IsInfinity(x) - the most obvious and, probably, the slowest because 2 method calls are involved.

  2. (*(((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 are:

  1. According to my research, this should precisely determine whether any given x is finite. Is this true?

  2. Is it the best possible way (performance-wise) to solve the task in IL, or is there a better (faster) solution?

P.S. I do appreciate recommendations to run my own benchmarks and find out, and will most certainly do this. Just thought maybe someone already had similar problem and knows the answer. P.P.S. Yes, I realize that we are talking abot nanoseconds here, and yes, they are important for my particular case

like image 956
Denis Yarkovoy Avatar asked Jun 18 '15 08:06

Denis Yarkovoy


2 Answers

Microsoft use 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;
}

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

like image 86
Thomas Ayoub Avatar answered Oct 27 '22 01:10

Thomas Ayoub


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

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

Explanation:

A double is a 64 bits value stored as:

  • 1 bit for the sign
  • 11 bits for the exponent
  • 52 bits for the 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 context:

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

Tests:

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
like image 23
alex Avatar answered Oct 26 '22 23:10

alex