6

This was a question in an exam but no clear explanation why. It was a true/false type question with;

There exists a value x of the type float for that holds: x + 1 == x...

Which is true. Why tho?

I guess it has to do with type conversion? But I can't imagine how that would work.

  • What's the largest possible float value plus one? – jonrsharpe Jul 26 '19 at 13:19
  • @jonrsharpe that value is undefined – 463035818_is_not_an_ai Jul 26 '19 at 13:38
  • I like this exam question. It can be rewritten as, "Why shouldn't you use float for keeping track of time?" – JohnFilleau Jul 26 '19 at 13:40
  • This is also related to comparing floats with equality being fraught with problems as well. This is due to the inaccuracy of representing numbers precisely. Good test question. – Demolishun Jul 26 '19 at 15:29
  • Possible duplicate of [Which is the first integer that an IEEE 754 float is incapable of representing exactly?](https://stackoverflow.com/questions/3793838/which-is-the-first-integer-that-an-ieee-754-float-is-incapable-of-representing-e) – Boann Jul 26 '19 at 16:15

4 Answers4

8

Sure.

#include <limits>
#include <iostream>
int main() {
    float f = std::numeric_limits<float>::infinity();
    std::cout << (f == f + 1) << std::endl;
}

As Deduplicator points out, if your float is big enough (works for me with float f = 1e20;), it'll also work because the added 1 would be outside of the float's accuracy.

Try it online

Blaze
  • 16,736
  • 2
  • 25
  • 44
  • 3
    No need to go to infinity, `1` pales to insignificance long before. Though admittedly, going all the way is simpler. – Deduplicator Jul 26 '19 at 13:24
  • @Deduplicator Thanks for pointing this out, I forgot about this. Added it to answer. I think that might have been the actual answer that OP's exam was looking for because it demonstrates the limitations of floating point numbers. – Blaze Jul 26 '19 at 13:30
  • 1
    Not all floating point representations support infinities either. In C++11, a value `x` for which `std::nextafter(x) - x > 2.0` will probably also give a value `x` for which `x == x + 1` will test true. – Peter Jul 26 '19 at 13:32
3

This code compiles without error:

#include <limits>

int main()
{
    static_assert(std::numeric_limits<float>::infinity() == std::numeric_limits<float>::infinity() + 1.0f, "error");
    static_assert(std::numeric_limits<double>::infinity() == std::numeric_limits<double>::infinity() + 1.0, "error");
    return 0;
}

online version


You don't need to even use infinity. If the number is big enough, rounding errors become big enough so adding one to the number doesn't change it at all. E.g.

static_assert(100000000000000000000000.f == 100000000000000000000000.f + 1.0, "error");

The specific number of 0 you have to put here may be implementation defined, though.

Always keep rounding in mind when you write programs that use floating point numbers.

Piotr Siupa
  • 3,929
  • 2
  • 29
  • 65
2
#include <iostream>

int main()
{
    float val = 1e5;
    while (val != val + 1)
        val++;
    std::cout << val << "\n";
    return 1;
}

Prints 1.67772e+07 for clang.

There exists a value x of the type float for that holds: x + 1 == x... which is true. Why tho?

The reason for that lies in how floating point numbers work. Basically a 32bit float has 24 bits for the mantissa (the base digits) and 8 bits for the exponent. At some point +1 just doesn't cause a change in the binary representation because the exponent is too high.

Timo
  • 9,269
  • 2
  • 28
  • 58
  • Yes, 2^24 = 16777216 and 16777217 can't be represented exactly with an IEEE754 32-bit float: `float(16777217) == 16777216.0`. The same holds for every odd number after that. – Bob__ Jul 26 '19 at 14:49
1

For a 32-bit IEEE754 float (a.k.a. single-precision or SP), the minumum non-negative normal such value is 16777216. That is, 16777216 + 1 == 16777216.

The number 16777216 is precisely 2^24. An SP float has 23 bits of mantissa. This is how it is represented internally:

                  3  2          1         0
                  1 09876543 21098765432109876543210
                  S ---E8--- ----------F23----------
          Binary: 0 10010111 00000000000000000000000
             Hex: 4B80 0000
       Precision: SP
            Sign: Positive
        Exponent: 24 (Stored: 151, Bias: 127)
       Hex-float: +0x1p24
           Value: +1.6777216e7 (NORMAL)

You can see the entire mantissa is 0. If you add 1 to this number, it'll hit the gap and be absorbed, giving you back precisely what you started with.

alias
  • 28,120
  • 2
  • 23
  • 40