Normalize integer types to float range
&lt;limits&gt; already provides a set of limits on values that can be stored in the various types. It's also a template, so it's easy to invoke on a template parameter. As a quick demo of that particular part of things:

template &lt;class T&gt;
void showminmax(T) { 
    std::cout &lt;&lt; "min: " &lt;&lt; std::numeric_limits&lt;T&gt;::min() &lt;&lt; 
               "\nmax: " &lt;&lt; std::numeric_limits&lt;T&gt;::max();
}

int main() { 
     std::cout &lt;&lt; "int\n";
     showminmax(1);

     std::cout &lt;&lt; "\nunsigned long long\n";
     showminmax(1ULL);
}


I believe the code to normalize the number to the range [0..1] can be simplified quite a bit as well, to something on this order:

template &lt;class T&gt;
float normalize(T t) {
    static_assert(std::is_integral&lt;T&gt;::value, "Input must be integral");
    float min = std::numeric_limits&lt;T&gt;::min();
    float max = std::numeric_limits&lt;T&gt;::max();
    float range = max - min;

    return (t - min) / range;
}


This should work for either signed or unsigned types. Here's a quick bit of demo code to exercise it, and show the results:

int main() {
    std::cout &lt;&lt; "char(min):   " &lt;&lt; normalize(std::numeric_limits&lt;char&gt;::min()) &lt;&lt; "\n";
    std::cout &lt;&lt; "char (1/4):  " &lt;&lt; normalize(char(std::numeric_limits&lt;char&gt;::min() &gt;&gt; 1)) &lt;&lt; "\n";
    std::cout &lt;&lt; "char (0):    " &lt;&lt; normalize('\0') &lt;&lt; "\n";
    std::cout &lt;&lt; "char (3/4):  " &lt;&lt; normalize(char(std::numeric_limits&lt;char&gt;::max() &gt;&gt; 1)) &lt;&lt; "\n";
    std::cout &lt;&lt; "char (max):  " &lt;&lt; normalize(std::numeric_limits&lt;char&gt;::max()) &lt;&lt; "\n\n";

    std::cout &lt;&lt; "int(min):   " &lt;&lt; normalize(std::numeric_limits&lt;int&gt;::min()) &lt;&lt; "\n";
    std::cout &lt;&lt; "int (1/4):  " &lt;&lt; normalize(std::numeric_limits&lt;int&gt;::min() &gt;&gt; 1) &lt;&lt; "\n";
    std::cout &lt;&lt; "int (0):    " &lt;&lt; normalize(0) &lt;&lt; "\n";
    std::cout &lt;&lt; "int (3/4):  " &lt;&lt; normalize(std::numeric_limits&lt;int&gt;::max() &gt;&gt; 1) &lt;&lt; "\n";
    std::cout &lt;&lt; "int (max):  " &lt;&lt; normalize(std::numeric_limits&lt;int&gt;::max()) &lt;&lt; "\n\n";

    std::cout &lt;&lt; "uint (0):   " &lt;&lt; normalize(0U) &lt;&lt; "\n";
    std::cout &lt;&lt; "uint (1/4): " &lt;&lt; normalize(std::numeric_limits&lt;unsigned int&gt;::max() / 4) &lt;&lt; "\n";
    std::cout &lt;&lt; "uint (mid): " &lt;&lt; normalize(std::numeric_limits&lt;unsigned int&gt;::max() / 2) &lt;&lt; "\n";
    std::cout &lt;&lt; "uint (max): " &lt;&lt; normalize(std::numeric_limits&lt;unsigned int&gt;::max()) &lt;&lt; "\n\n";


    std::cout &lt;&lt; "ULL (0):   " &lt;&lt; normalize(0ULL) &lt;&lt; "\n";
    std::cout &lt;&lt; "ULL (1/4): " &lt;&lt; normalize(std::numeric_limits&lt;unsigned long long&gt;::max() / 4) &lt;&lt; "\n";
    std::cout &lt;&lt; "ULL (mid):  " &lt;&lt; normalize(std::numeric_limits&lt;unsigned long long&gt;::max() / 2) &lt;&lt; "\n";
    std::cout &lt;&lt; "ULL (max):  " &lt;&lt; normalize(std::numeric_limits&lt;unsigned long long&gt;::max()) &lt;&lt; "\n";
}


Note that twos complement is asymmetric, so the values produced are technically just a tiny bit off (well, off from what you might expect, anyway). This will normally be lost in the rounding for any type with more than ~24 input bits, but if the input type is smaller than that (e.g., most implementations of char and short) a signed value of 0 won't give precisely 0 as the result (unless you have a machine with something like signed-magnitude or ones complement int, anyway).