0

The following loop would run only when off which is uint64_t is less than the value returned by ceil which is double. However I don't see the loop being executed.

#include <bits/stdc++.h>
using namespace std;

int main()
{
    uint64_t offset = 1164226701485, size = 945, div = 10000;
    for (uint64_t off = offset / div; off < ceil((float)(offset + size) / div); off++)
    {
        cout<<off;
    }
                            
    return 0;
}

SO I tried printing those values which seems correct to me and the loop should have been executed atleast once

cout.precision(17);
cout<< offset / div<<" "<< ceil((float)(offset + size) / div);

Output:

116422670 116422672

I am not really sure what's happening here, how can I make the loop to execute?

H Kumar
  • 37
  • 6
  • it is much easier to help you when you post a [mcve]. This is how far I got before loosing interest https://godbolt.org/z/MGPeaoxvM. You do not need to remove includes and the `main` you used to test the code. The main effect of doing this is that others have to add it back... – 463035818_is_not_an_ai Feb 07 '23 at 09:38
  • added MRE, I know now someone will come and say why using `bits/stdc++` is not a good idea – H Kumar Feb 07 '23 at 09:41
  • 2
    Problem is you are using `float` which has only `6`!!! significant digits! – Marek R Feb 07 '23 at 09:46
  • here you go [Why should I not `#include `?](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h). You understand why it is not a good idea? Because you ask a quesiton about C++ but your code wont compile with many C++ compilers. Thats quite a price to pay for not including 2-3 headers – 463035818_is_not_an_ai Feb 07 '23 at 09:48
  • @MarekR but here there are only 3 precision digits, `1164226702430/10000` = `116422670.243` which could decide that ceil will ultimately round off to nearest integer (greater) – H Kumar Feb 07 '23 at 09:52
  • 6 significant digits means you have `116422/10000` – Marek R Feb 07 '23 at 09:56
  • precision does not start to count after the `.` but at the first digit – 463035818_is_not_an_ai Feb 07 '23 at 09:57
  • using double would be a good idea here or increase significant for float? – H Kumar Feb 07 '23 at 09:59
  • why use floating point numbers in the first place? Use integers if you care about exact numbers. Using floating point numbers in loop conditions is a source of bugs and better avoided – 463035818_is_not_an_ai Feb 07 '23 at 10:02
  • because I want the values after decimal so that ceil can translate it to next integer(greater) – H Kumar Feb 07 '23 at 10:04
  • no floating point number is needed to get `1164226702` from `1164226701485` – 463035818_is_not_an_ai Feb 07 '23 at 10:05
  • To perform integer division with rounding up, use `(offset + size - 1) / div + 1`. This requires the numerator to be always positive, which your variable names suggest will be true. – Eric Postpischil Feb 07 '23 at 22:47

2 Answers2

2

Problem is this expression:

off < ceil((float)(offset + size) / div)

note that on one side of this comparation you have uint64_t on other float.

Before compare can be done common type has to be selected. It is a float.

So your value on the left: 116422670 is converted to float. Since float has only 6 significant digits, result is rounded to nearest value which can be represented in float.

It happens to be: 116422672f.

Demo: https://godbolt.org/z/xhEnMKE8e

It is hard to spot rounding issue when watching decimal value so take a look on this: https://godbolt.org/z/TTEqvx1vG

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • When you set precision to 17, `cerr.precision(17);` why `static_cast(offset / div)` still gives us `116422672` – H Kumar Feb 07 '23 at 10:53
  • `cerr.precision(17);` was just copied from your example and left so it is possible to test `double` too. – Marek R Feb 07 '23 at 10:57
  • Also wdym when you say `result is rounded to nearest value which can be represented in float` – H Kumar Feb 07 '23 at 10:57
  • This is how floating point work. The have some set of value which they can represent. Results of calculation are always rounded to nearest value which can be represented by given floating point type. It is same as thing as show `1/3` in decimal form using finite amount of digits. – Marek R Feb 07 '23 at 10:59
  • Try also [this site](https://cppinsights.io/s/4d187323). – Marek R Feb 07 '23 at 11:04
  • When you say `on other float.` ceil returns us a double and not float then why was it not converted to double – H Kumar Feb 07 '23 at 11:08
  • Please [read documentation of std::ceil](https://en.cppreference.com/w/cpp/numeric/math/ceil). It has overloads for `float`, `double` and `long double`! – Marek R Feb 07 '23 at 11:25
  • My bad, I just looked at first link which popped up and it said ceil returns a double. Sorry I did not search further. Thank you for helping me out. – H Kumar Feb 07 '23 at 11:26
1

how can I make the loop to execute?

Alternative to fixing floating point math: do not use floating point math for an integer problem.

In this case, use off scaled by div.

// for (uint64_t off = offset / div; off < ceil((float)(offset + size) / div); off++) {
//    cout<<off;
// }

for (uint64_t off = offset; off < offset + size; off += div)
    cout << off/div;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256