Rob The Quant
Rob The Quant

Reputation: 397

What is the fastest way to discretize double in C#?

I have a double between -1 and 1.

I need to discretize it by N steps it really, really fast. If N is 5 my end values would be one of these:

-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8,1

I need a function:

double discretize(double value)

so that for example:

discretize(0.091231) = 0
discretize(0.192312) = 0.2

I wonder if there's any trick with the mantissa/exponent, to make it discrete with bit shifts etc... without making any floating-point arithmetics.

Upvotes: 0

Views: 398

Answers (2)

Rob The Quant
Rob The Quant

Reputation: 397

Fastest method so far:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Quantize(this double x, int steps)
{
    return ((double)((int)(x*steps+0.5)))/steps;
}

Upvotes: 0

John Alexiou
John Alexiou

Reputation: 29254

Sounds like a rounding operation.

static class Program
{
    static readonly Random rng = new Random();
    static void Main(string[] args)
    {
        for (int i = 0; i < 15; i++)
        {
            var x = rng.NextDouble();
            Debug.WriteLine($"{x,-15} = {x.Quantize(5)}");
        }
    }

    public static double Quantize(this double x, int steps)
    {
        return Math.Round(x*steps)/steps;
    }
}

with the program output

0.45652442819277 = 0.4
0.649511796259094 = 0.6
0.605691870490877 = 0.6
0.685007393679119 = 0.6
0.489223629929695 = 0.4
0.496371834304357 = 0.4
0.153276258685289 = 0.2
0.212714763457288 = 0.2
0.0338650732458872 = 0
0.0612733452866195 = 0
0.258718123314305 = 0.2
0.906546349593693 = 1
0.39698489727312 = 0.4
0.728462797928817 = 0.8
0.140497107589849 = 0.2

PS. Since you are doing division after the round it might better to use the ToEven option

Math.Round(x*steps, MidpointRounding.ToEven)/steps

If you want fast speed then switch from double to float and use the functions in System.Numerics to load multiple values in vectors.

Also decorate the functions with aggressive inlining which in turn has a better chance to produce vectorized code by the JIT.

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static double Quantize(this double x, int steps)
    {
        return Math.Round(x*steps)/steps;
    }

Finally, consider doing this math processing with C++ or even better Fortran (maybe even Julia) using a library.

Upvotes: 1

Related Questions