Calculate min/max values for signed or unsigned integral number with any valid number of bits (up to 64) This came up when I answered another post.

Is there a better way?

public class Bits
{
    public static void MinMaxI(ulong _bits, out long _min, out long _max)
    {
        // ? unsigned range with at least one value bit
        if (_bits &lt; 2 || _bits &gt; 64)
        {
            throw new System.ArgumentOutOfRangeException("_bits", _bits,
             String.Format("2 &lt;= _bits &lt;= 64"));
        }

        _min = (long)1 &lt;&lt; (int)(_bits - 1);
        _max = -1 - _min;
    }


    public static long MinI(ulong _bits)
    {
        // ? unsigned range with at least one value bit
        if (_bits &lt; 2 || _bits &gt; 64)
        {
            throw new System.ArgumentOutOfRangeException("_bits", _bits,
             String.Format("2 &lt;= _bits &lt;= 64"));
        }

        return (long)1 &lt;&lt; (int)(_bits - 1);
    }


    public static long MaxI(ulong _bits)
    {
        // ? unsigned range with at least one value bit
        if (_bits &lt; 2 || _bits &gt; 64)
        {
            throw new System.ArgumentOutOfRangeException("_bits", _bits,
             String.Format("2 &lt;= _bits &lt;= 64"));
        }

        return -1 - ((long)1 &lt;&lt; (int)(_bits - 1));
    }


    public static ulong MaxN(ulong _bits)
    {
        // ? unsigned range with at least one value bit
        if (_bits &lt; 1 || _bits &gt; 64)
        {
            throw new System.ArgumentOutOfRangeException("_bits", _bits,
             String.Format("1 &lt;= _bits &lt;= 64"));
        }

        return _bits == 64 ? ~(ulong)0 : ~(~(ulong)0 &lt;&lt; (int)_bits);
    }
}
First of all, I think there are misprints in your code that maximums are negative and minimums are positive.

Next. Since you need MinI, MaxI and MaxN values for a few bits only, it makes sense to calculate these values apriory. In this case we can use loop for calculation.
In the following code I've used recurrent formulas for calculation, which are much more readable in my opinion:

public class Bits
{
    public const int MaxBits = 64;

    public static readonly ReadOnlyCollection&lt;long&gt; MinI;
    public static readonly ReadOnlyCollection&lt;long&gt; MaxI;
    public static readonly ReadOnlyCollection&lt;ulong&gt; MaxN;

    static Bits()
    {
        long[] minI = new long[MaxBits + 1];
        long[] maxI = new long[MaxBits + 1];
        ulong[] maxN = new ulong[MaxBits + 1];

        maxN[1] = 1;

        for (int i = 2; i &lt; MaxBits; i++)
        {
            maxI[i] = maxI[i - 1] * 2 + 1;
            minI[i] = -maxI[i] - 1;
            maxN[i] = maxN[i - 1] * 2 + 1;
        }

        maxI[MaxBits] = long.MaxValue;
        minI[MaxBits] = long.MinValue;
        maxN[MaxBits] = ulong.MaxValue;

        MinI = new ReadOnlyCollection&lt;long&gt;(minI);
        MaxI = new ReadOnlyCollection&lt;long&gt;(maxI);
        MaxN = new ReadOnlyCollection&lt;ulong&gt;(maxN);
    }
}


Usage:

Console.WriteLine(Bits.MinI[3]);
Console.WriteLine(Bits.MaxI[3]);
Console.WriteLine(Bits.MaxN[3]);


Output:

-4
3
7


The only difference in functionality I can see is that arrays have values for bits 0 and 1.
Hope it is not a problem for you.