Search code examples
c++cmathfloating-pointieee-754

Is there a value of type `double`, `K`, such that `K * K == 3.0`?


Is there a value of type double (IEEE 64-bit float / binary64), K, such that K * K == 3.0? (The irrational number is of course "square root of 3")

I tried:

static constexpr double Sqrt3 = 1.732050807568877293527446341505872366942805253810380628055806;
static_assert(Sqrt3 * Sqrt3 == 3.0);

but the static assert fails.

(I'm guessing neither the next higher nor next lower floating-point representable number square to 3.0 after rounding? Or is the parser of the floating point literal being stupid? Or is it doable in IEEE standard but fast math optimizations are messing it up?)

I think the digits are right:

$ python

>>> N = 1732050807568877293527446341505872366942805253810380628055806
>>> N * N
2999999999999999999999999999999999999999999999999999999999996\
607078976886330406910974461358291614910225958586655450309636

Update

I've discovered that:

static_assert(Sqrt3 * Sqrt3 < 3.0); // pass
static_assert(Sqrt3 * Sqrt3 > 2.999999999999999); // pass
static_assert(Sqrt3 * Sqrt3 > 2.9999999999999999); // fail

So the literal must produce the next lower value.

I guess I need to check the next higher value. Could bit-dump the representation maybe and then increment the last bit of the mantissa.

Update 2

For posterity: I wound up going with this for the Sqrt3 constant and the test:

static constexpr double Sqrt3 = 1.7320508075688772;
static_assert(0x1.BB67AE8584CAAP+0 == 1.7320508075688772);
static_assert(Sqrt3 * Sqrt3 == 2.9999999999999996);

Solution

  • Testing with Python is valid I think, since both use the IEEE-754 representation for doubles along with the rules for operations on same.

    The closest possible double to the square root of 3 is slightly low.

    >>> Sqrt3 = 3**0.5
    >>> Sqrt3*Sqrt3
    2.9999999999999996
    

    The next available value is too high.

    >>> import numpy as np
    >>> Sqrt3p = np.nextafter(Sqrt3,999)
    >>> Sqrt3p*Sqrt3p
    3.0000000000000004
    

    If you could split the difference, you'd have it.

    >>> Sqrt3*Sqrt3p
    3.0