0

In C, the following gives me an implicit conversion warning. I know why this warning happens. What I want to know is if there's a reliable one liner way of getting the percentage of really large unsigned numbers. I know that the end result will fit into unsigned long long, the same can't be said of the intermediate operations.

#define LOAD_FACTOR 0.75
#define MAX_CAPACITY (unsigned long long)((unsigned long long)-1 / sizeof(Entry) * LOAD_FACTOR)

Entry just being a normal struct, any struct will do.

I'm thinking about:

#define MAX_CAPACITY ((unsigned long long)-1 / sizeof(Entry) / 2 + (unsigned long long)-1 / sizeof(Entry) / 4)

But this way the LOAD_FACTOR becomes, well, not "dynamic".

EDIT: I'm compiling with Wall, Werror, Wextra and Wpedantic

João Pires
  • 927
  • 1
  • 5
  • 16
  • 1
    Why must it be a one-liner? Is it for code golf or what? – Lundin Jul 06 '21 at 13:42
  • Tried it on a few compilers without a problem . Here https://godbolt.org/z/71enWdvrh – Edgen Jul 06 '21 at 13:43
  • 1
    "I know why this warning happens." Ok why? Because it isn't obvious no me. The only obvious implicit conversion here is the conversion to float. – Lundin Jul 06 '21 at 13:44
  • Ok, I will lift that requirement, it can be a function too. I'll just the initialize the value just once instead of making it a macro. – João Pires Jul 06 '21 at 13:45
  • @Lundin, a `double` only has 53 bits of mantissa while an `unsigned long long` needs 64 bits, `clang` is, at compile time, flaging this as a warning to me. – João Pires Jul 06 '21 at 13:48
  • @Edgen, the warning is still appearing there. – João Pires Jul 06 '21 at 13:49
  • `(unsigned long long)-1 / sizeof(Entry)` is however an integer constant expression so it isn't obvious why it wouldn't fit. Though any implicit conversions from unsigned int types to floating point or the other way around are generally fishy. – Lundin Jul 06 '21 at 13:52
  • #define MAX_CAPACITY (unsigned long long)((unsigned long long)-1 /(unsigned long long) sizeof(Entry) *(unsigned long long) LOAD_FACTOR) seems to sort it out – Edgen Jul 06 '21 at 13:56
  • 1
    @Edgen `0.75` converted to `unsigned long long` is truncated to `0`. – João Pires Jul 06 '21 at 13:57
  • @Lundin the conversion happens when you multiply with `LOAD_FACTOR` which is a `float` here. The result of any integer multiplication with a `float` or `double` is always a `float` or `double`, and well, in this case the result is too large to fit into a `double`. – João Pires Jul 06 '21 at 13:59
  • They're the same for all effects. Because `clang` is flagging it as a warning and I'm treating warnings as errors: `error: implicit conversion from 'unsigned long long' to 'double' changes value from 1152921504606846975 to 1152921504606846976 [-Werror,-Wimplicit-const-int-float-conversion]` – João Pires Jul 06 '21 at 14:09
  • Then convert explicitly. `(double)(something..)` – KamilCuk Jul 06 '21 at 14:32
  • Instead of `LOAD_FACTOR` as `0.75`, express as `LF/power_of_2` and then `(unsigned long long)-1 / power_of_2 * LF + (unsigned long long)-1 % power_of_2 * LF / power_of_2`. – chux - Reinstate Monica Jul 06 '21 at 14:33

0 Answers0