0

When you add in C++ too number that will have a result bigger than the maximum of int_64, I go in negative values.

We have a project to build a compiler and we read the string and try to transform it in expressions. We need to be able to transform a string in a int_64 and if it is bigger the maximum value, instead of giving a error, to go to negative values.

For example if I have a string s = "9223372036854775808" I need to be able to transform it in int_64 but have the value -9223372036854775808, but the normal transformations give me an error.

I thought at doing it like 9223372036854775808 = 9*10^18+2*10^17....+8, but are there easier solutions?

  • should not you convert max int64 into string, then compare string literal with this string to check whether string can be converted into int64. if you start converting string into int64 without knowing it can be converted, you'll get overflow, which is ub, if memory serves me. – Andrew Kashpur Mar 26 '18 at 09:40
  • If I were you, I ll write a class named `BigNumber`, which has `operator +(const BigNumber &)` and `to_string()` functions. With this class, you can do things like this: `BigNumber n1(12), b2(34), b3(n1 + n2);` Ofc, if you do so, you need to figure out the detail about why a big number can be a negative value, you need to realize this into the constructor of this class. – Yves Mar 26 '18 at 09:40
  • 2
    beware, _signed_ integer overflow is undefined behavior – YSC Mar 26 '18 at 09:40
  • Parse it as uint64_t and then cast to int64_t, though it is not clear why would you want to perform such a conversion. – user7860670 Mar 26 '18 at 09:41
  • 1
    *"compiler"* Hm, I am not sure if this is the appropriate behaviour for such software. Possibly better to refuse to compile, if literals are too large... Not 100% about now, I think this is what C or C++ standard do require. Well, your compiler likely is for another language anyway, but still... – Aconcagua Mar 26 '18 at 10:18
  • Take a look at [GMP](https://gmplib.org) if you need to work with numbers larger than `int64_t`. – Jesper Juhl Mar 26 '18 at 11:07

2 Answers2

1

Signed integer overflow is undefined behaviour! "Going" into negative numbers is just one possible outcome, anything else, including switching off the sun, could happen as well...

Unsigned integer overflow, in contrast, is well defined. So you could use uint64_t instead and calculate the appropriate negative value from, if the value is greater than std::numeric_limits<int64_t>::max().

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
0

If you run the following code

#include <string>
#include <sstream>
#include <iostream>

int main() {
    std::string small = "9223372036854775807";
    std::string s = "9223372036854775808";

    {
        std::istringstream stream(small);
        std::int64_t i;
        stream >> i;

        if (stream) {
            std::cout << "ok" << std::endl;
        }

        std::cout << stream.fail() << std::endl << i << std::endl;
    }


    {
        std::istringstream stream(s);
        std::int64_t i;
        stream >> i;

        if (!stream) {
            std::cout << "error" << std::endl;
        }

        std::cout << stream.fail() << std::endl << i << std::endl;
    }

    return 0;
}

you will see that you cannot parse the number into a std::int64_t and that the stream correctly reports an error. You just cannot read a number that is larger than the maximum number into a std::int64_t.

In general, integer overflow is undefined behavior in C++, so

When you add in C++ too number that will have a result bigger than the maximum of int_64, I go in negative values.

is not true for signed integer arithmetics. If you need that you must resort to unsigned arithmetics.

As Aconcagua points out in the comment operator>> for std::uint64_tdoes not wrap-around, so you could read astd::uint64_tif the numbers are smaller thannumeric_limits::max()and [convert it toint64_t`]2. If the number are larger, you probably need to implement a custom type for big integers (or use an existing implementation, e.g. The GNU Multiple Precision Arithmetic Library.

Jens
  • 9,058
  • 2
  • 26
  • 43
  • Be aware that `operator>>` is not suitable even for unsigned integers, as you won't get overflow, but `std::numeric_limits::max()` instead, if the value is too large to be represented... – Aconcagua Mar 26 '18 at 09:59
  • @Aconcagua Thanks, I didn't know that (and edited the answer assuming that it does wrap around...). I've changed the answer and removed that part. – Jens Mar 26 '18 at 10:03
  • A little bit unprecise, though: `std::uint64_t` *does* wrap around if used in arithmetics... It is `operator>>` does show such behaviour if value in string is too large. And there is no need for a separate type either; just parse *manually*, starting at the string's end (`v = v * 10 + c;`) and let the uint64_t wrap around, if need be. When done, convert to signed integer... – Aconcagua Mar 26 '18 at 10:11