5

I'm currently writing a program that needs to take the floor of a square root. Since the value I'm taking the square root of is positive, I just cast it to int. So say for the following example:

int i = 16;
int j = std::sqrt(i)

j should be 4.

I am wondering though, is it possible that sqrt returns 3.9999999991 instead of 4.000000001 or whatever, and the result of j is 3? Is there rules defining floating point behaviour? How can I properly convert this to an int?

JamesLens
  • 447
  • 6
  • 14
  • 9
    int integer = std::round(floating_point); –  Mar 05 '15 at 20:16
  • Somewhat relevant if you care about rounding : https://stackoverflow.com/questions/485525/round-for-float-in-c – tux3 Mar 05 '15 at 20:16
  • @DieterLücking I think that would round to *nearest*, while the desired result here is to round down from what would be the "true" square root. E.g. sqrt(16) -> 4, sqrt(15) ->3 – Drew Dormann Mar 05 '15 at 20:19
  • 1
    @DrewDormann Right, that is the desired result. I already considered doing the +0.5 approach, but it wouldn't work here because sqrt(15) = 3.87 + 0.5 = 4.37 which casts to 4 instead of 3 as needed. – JamesLens Mar 05 '15 at 20:26

1 Answers1

4

Almost all widely available hardware uses IETF754 floating point numbers, although C++ does not require it.

Assuming IETF754 floating point numbers and a direct mapping of ::std::sqrt to the IETF754 floating point square root operation, you are assured of the following:

  • 16 and 4 can both be represented exactly in floating point arithmetic - in fact, double precision floating point numbers can represent any 32 bit integer exactly
  • the square root returns the result that is closest to being exact

Therefore, your example will work fine.

In general, the problem you have hinted at might happen, but to solve it you have to ask a bigger question: Under which circumstances is a number that is close to integral, really integral?

This is actually harder than it might seem, since you want to compute the floor of the square root, and therefore simply rounding will not work for you. However, once you have answered this question for yourself, implementing a solution should be rather simple. For example:

int i = 16;
int j = std::sqrt(i);
if((j + 1) * (j + 1) == i) j += 1;
danielschemmel
  • 10,885
  • 1
  • 36
  • 58