Search Unity

Issue with max int value and clamping

Discussion in 'Scripting' started by ADNCG, Jun 28, 2019.

  1. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    994
    The behaviour with adding to an int beyond the max value seems to be that the int resets to its min value and then adds whatever was leftover.

    e.g.
    Code (CSharp):
    1. int fubar = int.MaxValue;
    2. fubar++;
    3. Debug.Log(fubar); // prints -2147483648
    In my high score chaser, I'm clamping the high score between 0 and 2 billion. My problem is that there's this combo mechanic that can add insane values bringing the score way above the max.

    My issue is here: Say current score is 2 billion and combo is 500 million, I can't Clamp(currentScore + combo, 0, int.MaxValue) because of the reason that I listed above. It'll bring the int back to a negative value since it goes beyond the max allowed and then it is clamped at 0 since it's considered below the min value rather than above the max value.

    How do you cap an int at max value?

    Using a long int could lead to the same issues in my case since the combo mechanic scales exponentially and theoretically could also end up busting the long's limit. Less likely but still possible.

    edit : I could add to the value with increments of 1 as long as value < int.MaxValue. This way I'd never get to the point where the int wraps over. Still holding out hope that there's a cleaner/more performant way to achieve this though.
     
    Last edited: Jun 28, 2019
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    First off, if your scores can get so big that even long int's aren't enough, that's just straight up absurd and you may want to reconsider the way scores work. Unless, of course, that's the joke.

    So this is basically a fundamental limit of the int and long data types and just sort of... the way computers compute. You could try to detect that an operation will exceed MaxValue and then return MaxValue if so, but that is tricky to say the least.

    But, there is a class called BigInteger that is designed to be arbitrarily large, where the only limit is your computer's memory. If you're gonna have comically large numbers, you may as well actually support comically large numbers - it'd be a huge buzzkill for players word hard to rack up obscene multipliers only to find out that they hit some arbitrary limit a long time ago. And at a glance, it seems like implementing BigInteger for your scores would probably be easier than attempting to figure out how to cap scores at MaxValue.
     
    ADNCG likes this.
  3. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    There is a keyword in C# called checked that you can use to detect overflows and raise an exception if they occur. (Note: exceptions are kinda expensive compared to other methods of controlling program flow.)

    Don't forget that your "combo" variable might itself overflow before you try to add it to currentScore.


    Also StarManta makes some good points re: do you really want your numbers to get that big, and if so do you really want to cap them.
     
    ADNCG and StarManta like this.
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Huh, TIL. Good to know that exists!
     
  5. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Also want to point out that you are making a bad assumption here, which is that your score cap has to equal the maximum value that can be stored in whatever variable you are using. If you stored your score in a long but capped it to int max then this would probably be really easy.

    First figure out what you want the cap to be, then choose the data type you're going to use to store it.
     
    Joe-Censored, Suddoha and ADNCG like this.
  6. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    It seems you might already get into trouble calculating the combo score if you say it can grow that much, if you want to work in the range of int32?
    So you'd need to define (for your system) that the max is int.MaxValue for the combo as well.

    If you worked that out, you can do the following:

    Code (csharp):
    1. int score = ...
    2. int combo = ...
    3.  
    4. score = ((long)score + combo < int.MaxValue)? score + combo : int.MaxValue;
     
    ADNCG likes this.
  7. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    994
    In my current setup I've clamped the combo as well. There's another mechanic to be factored in, I just didn't want to go into details.

    Basically the user makes stacks that can pretty much be infinite. If they destroy the stack, the code is amount in stack * current combo value.

    I could probably iterate over the amount of the stack and increment it progressively since individually there's no way I could overflow with current score + one instance of the current combo. Feels pretty ugly though.

    Anyway, I'm going with BigInteger. I didn't know that was an option and I'd much rather not have to cap the score.

    The checked keyword is also a super valuable piece of info, thank you for sharing.

    Thanks to all.
     
    Last edited: Jun 28, 2019