1

I have encountered issues in the past multiplying literals by one billion, where the result should be 64-bits but was converted to 32 bits due to the presence of literals.

What is the best (safest & simplest) practice when multiplying numbers which will probably exceed 2^32?

I have this equation:

const uint64_t x = 1'000'000'000 * 60 * 5;

I have opted for:

const uint64_t x = static_cast<uint64_t>(1'000'000'000) * 60 * 5;

Is this how it should be done? Only one of the multiplicands needs to be cast to 64 bits?

user997112
  • 29,025
  • 43
  • 182
  • 361

1 Answers1

2

You can use a suffix on the first literal to promote it to the correct size. In this case you can use

const uint64_t x = 1'000'000'000ull * 60 * 5;

to make 1'000'000'000 an unsigned long long which is at least 64 bits wide. This also has the affect of promoting 60 and 5 to be unsigned long long's as well when the multiplication is done.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • I have a additional question: `const uint64_t x{ 1'000'000'000 * 60 * 5};` if number in curly races will exceed `uint64`, will compilator raise warning or error? In my opinion it can be staticly deduced – Krzysztof Mochocki Sep 03 '20 at 14:42
  • @KrzysztofMochocki using `{}` ensures that the code won't compile if this value doesn't fit into a `uint64_t`. – Jan Schultke Sep 03 '20 at 14:42
  • 2
    @KrzysztofMochocki `{ 1'000'000'000 * 60 * 5}` will produce an `int` as that is the type of all of the operands. This means it will overflow. – NathanOliver Sep 03 '20 at 14:43
  • so it should not compile even without `ull` literal? – Krzysztof Mochocki Sep 03 '20 at 14:43
  • @NathanOliver *might overflow. It might also not overflow. – Jan Schultke Sep 03 '20 at 14:44
  • 2
    @KrzysztofMochocki it will compile, it just most likely not give you what you want. – NathanOliver Sep 03 '20 at 14:44
  • 2
    @KrzysztofMochocki the value of all operands in the curly brackets is `int`, so the result will also be `int`. Converting to `uint64_t` using curly brackets just ensures that this result will fit into whatever type a `uint64_t` is. This **will** compile, because regardless of whether the multiplication overflows, the value fits into a 64-bit integer. `int` is most likely 32-bits if you're using a modern architecture, so this multiplication will probably overflow. The right thing to do is instead `uint64_t{1000000000} * 60 * 5`. – Jan Schultke Sep 03 '20 at 14:47