In learning how floating point numbers are represented in computers I have come across the term "bias value" that I do not quite understand.
The bias value in floating point numbers has to do with the negative and positiveness of the exponent part of a floating point number.
The bias value of a floating point number is 127, which means that 127 is always added to the exponent part of a floating point number. How does doing this help determine if the exponent is negative or positive or not?
In floating-point arithmetic, a biased exponent is the result of adding some constant (called the bias) to the exponent chosen to make the range of the exponent nonnegative. Biased exponents are particularly useful when encoding and decoding the floating-point representations of subnormal numbers.
The bias value allows the activation function to be shifted to the left or right, to better fit the data. Hence changes to the weights alter the steepness of the sigmoid curve, whilst the bias offsets it, shifting the entire curve so it fits better.
The biased exponent is used for the representation of negative exponents. The biased exponent has advantages over other negative representations in performing bitwise comparing of two floating point numbers for equality. The range of exponent in single precision format is -128 to +127.
A floating point number, is a positive or negative whole number with a decimal point. For example, 5.5, 0.25, and -103.342 are all floating point numbers, while 91, and 0 are not. Floating point numbers get their name from the way the decimal point can "float" to any position necessary.
b0lt has already explained how bias works. At a guess, perhaps you'd like to know why they use a bias representation here, even though virtually all modern computers use two's complement essentially everywhere else (and even machines that don't use two's complement, use one's complement or sign-magnitude, not bias).
One of the goals of the IEEE floating point standards was that you could treat the bits of a floating point number as a (signed) integer of the same size, and if you compared them that way, the values will sort into the same order as the floating point numbers they represented.
If you used a twos-complement representation for the exponent, a small positive number (i.e., with a negative exponent) would look like a very large integer because the second MSB would be set. By using a bias representation instead, you don't run into that -- a smaller exponent in the floating point number always looks like a smaller integer.
FWIW, this is also why floating point numbers are typically arranged with the sign first, then the exponent, and finally the significand in the least significant bits--this way, you can take positive floating point numbers, treat those bits as integers, and sort them. When you do so, the result will have the floating point numbers in the correct order. For example:
#include <vector> #include <algorithm> #include <iostream> int main() { // some arbitrary floating point values std::vector<double> vals = { 1e21, 1, 2.2, 2, 123, 1.1, 0.0001, 3, 17 }; std::vector<long long> ivals; // Take those floating point values, and treat the bits as integers: for (auto &&v : vals) ivals.push_back(*reinterpret_cast<long long *>(&v)); // Sort them as integers: std::sort(ivals.begin(), ivals.end()); // Print out both the integers and the floating point value those bits represent: for (auto &&i : ivals) std::cout << i << "\t(" << *reinterpret_cast<double *>(&i) << ")\n"; }
When we run this, the result looks like this:
4547007122018943789 (0.0001) 4607182418800017408 (1) 4607632778762754458 (1.1) 4611686018427387904 (2) 4612136378390124954 (2.2) 4613937818241073152 (3) 4625478292286210048 (17) 4638355772470722560 (123) 4921056587992461136 (1e+21)
As you can see, even though we sorted them as integers, the floating point numbers that those bits represent also come out in the correct order.
This does have limitations with respect to floating point numbers. While all (non-ancient) computers agree on the representation of positive numbers, there are three representations that have (fairly recently) been used for signed numbers: signed magnitude, one's complement, and two's complement.
Just treating the bits as an integer and comparing will work fine on a computer that uses signed magnitude representation for integers. For computers that use one's complement or two's complement, negative numbers will sort in inverted order. Since this is still a simple rule, it's pretty easy to write code that works with it. If we change the sort
call above to something like this:
std::sort(ivals.begin(), ivals.end(), [](auto a, auto b) { if (a < 0.0 && b < 0.0) return b < a; return a < b; } );
...it will then correctly sort both positive and negative numbers. E.g., input of:
std::vector<double> vals = { 1e21, 1, 2.2, 2, 123, 1.1, 0.0001, 3, 17, -0.001, -0.00101, -1e22 };
Will produce a result of:
-4287162073302051438 (-1e+22) -4661071411077222194 (-0.00101) -4661117527937406468 (-0.001) 4547007122018943789 (0.0001) 4607182418800017408 (1) 4607632778762754458 (1.1) 4611686018427387904 (2) 4612136378390124954 (2.2) 4613937818241073152 (3) 4625478292286210048 (17) 4638355772470722560 (123) 4921056587992461136 (1e+21)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With