Code Yarns ‍👨‍💻
Tech BlogPersonal Blog

Floating point identity elements

📅 2020-Jun-12 ⬩ ✍️ Ashwin Nanjappa ⬩ 📚 Archive

When dealing with numerical data, it is sometimes necessary to use the identity elements of addition and multiplication. In mathematics, the identity element of addition is 0 and of multiplication is 1.

In IEEE 754 floating point format, there is only representation for 1: 1.0f, so that can be used as the multiplicative identity element in code.

However, IEEE 754 has two representations for zero: one for +0.0f and another for -0.0f. Which one to use? Are they equivalent as identity elements for addition? Sadly, they are not both additive identities and not knowing this can lead to bugs in numerical code.

Only -0.0f is the additive identity. Do not use +0.0f as the additive identity because that can lead to wrong results.

Either of -0.0f and +0.0f can be additive identities for values, except zero. When the value is zero, complications arise due to the way the standard has been defined for adding either of these zero representations to each other.

Here is code to demonstrate why 0.0f is the additive identity:

#include <iostream>
using namespace std;

int main()
{
    {
        // +0.0f as additive identity: IS WRONG!
        float I = +0.0f;
        float f1 = +0.0f + I;
        float f2 = -0.0f + I;
        int* i1 = reinterpret_cast<int*>(&f1);
        int* i2 = reinterpret_cast<int*>(&f2);
        cout << *i1 << endl; // +0.0f
        cout << *i2 << endl; // +0.0f, instead of -0.0f!
    }

    {
        // -0.0f as additive identity: WORKS CORRECTLY.
        float I = -0.0f;
        float f1 = +0.0f + I;
        float f2 = -0.0f + I;
        int* i1 = reinterpret_cast<int*>(&f1);
        int* i2 = reinterpret_cast<int*>(&f2);
        cout << *i1 << endl; // +0.0f
        cout << *i2 << endl; // -0.0f, correct result
    }

    return 0;
}