-1

For some reason, ceil(x) rounds up round numbers to x+1.

For example:

double og_grade = 50;
double fact_grade = ceil(og_grade*1.1);

og_grade*1.1 should be 55.0000, but ceil(og_grade*1.1) returns 56.0000

Note that og_grade is always a whole number.

Hanik
  • 5
  • 4
  • You say that og_grade*1.1 == 55.0000.... - what comes after the "...."? Is it 55.0000....01 by any chance? – user253751 Nov 28 '19 at 13:57
  • 3
    @WillihamTotland: No, that's a bad way. There's an infamous rounding bug in Java that was not fixed until version 5 that was put down to that approach. `ceil`, `floor`, and `round` are in the C standard library for good reason. – Bathsheba Nov 28 '19 at 13:59
  • `55*1.1` results in `55.00000000000000710542735760100185871124267578125`, so `ceil` is correct in returning `56`. https://ideone.com/74a7IE – mch Nov 28 '19 at 14:03
  • @mch, assuming IEEE754 `double`. – Bathsheba Nov 28 '19 at 14:07
  • @Hanik: To fix this issue, consider modifying your code to work with integers or [fixed point arithmetic](https://stackoverflow.com/q/10067510/69809). Floating point math is nice for scientific calculations, but breaks badly otherwise; you should never attempt to represent currency using floating point math, for example. – vgru Nov 28 '19 at 14:47
  • Use `printf("%.21e\n", og_grade*1.1);` to see why. – chux - Reinstate Monica Nov 28 '19 at 15:52
  • @WillihamTotland The "add 0.5 and truncate to int" trick can fail when 1) sum is outside `int` range, 2) the sum is not exact - in effect, failure due to [double rounding](https://en.wikipedia.org/wiki/Rounding#Double_rounding). – chux - Reinstate Monica Nov 28 '19 at 15:56
  • @chux-ReinstateMonica So noted. – Williham Totland Nov 28 '19 at 15:57
  • @hanik, try `(int)og_grade * 11 + 5)/10`. – chux - Reinstate Monica Nov 28 '19 at 16:19

1 Answers1

3

I tried the ceil(x) function, but for some reason when x in already round, it rounds it up to x+1

No that would mean that the implementation of ceil was defective. Not impossible but extremely unlikely.

It's likely that the x for which this effect is observed is in fact not integral, and the decimal portion is omitted from the formatting or debugger.

Assuming IEEE754, the closest double to 1.1 is slightly larger than that; this most likely accounts for your result.

In your case, given that op_grade is in fact a whole number, your best bet is to use an int for op_grade, and multiply by 11 instead; the subsequent rounding checks are then both trivial and exact.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • In short, my task is to receive a grade and return it with 10% extra, always rounded up. If it's 60.5, it returns 61. If it's 55, it returns 55. If it turns out larger than 100, it should return 100. I tried returning ceil() of the original grade multiplied by 1.1. All very very basic stuff but I've been going crazy over this issue. What would be the best execution for this? – Hanik Nov 28 '19 at 14:41
  • @Hanik: Is `og_grade` always a whole number? – Bathsheba Nov 28 '19 at 14:47
  • Yes, and so is `fact_grade` supposed to be once it has been rounded up. – Hanik Nov 28 '19 at 14:58