1

How to detect overflow in a function when n becomes greater than 64 bits?

uint64_t col(uint64_t n) 
{
    int count = 0;

    while (n != 1) {
        if (n % 2 == 0) {
            n /= 2;
        } else {
            n = (3 * n) + 1;
        }
        count++;
    }
    return count;
}
12
  • What operations are you running that might overflow? Please show the relevant code. Commented May 4, 2022 at 20:32
  • 2
    Please edit your code into the question and format it properly. Commented May 4, 2022 at 20:33
  • @dbush I have included it my question. What if n becomes greater than 64 bits during the while loop and how can I detect it in this case? Commented May 4, 2022 at 20:35
  • thank you ill do that next time @DavidGrayson Commented May 4, 2022 at 20:38
  • 1
    Why have you made your question essentially useless by deleting the whole body? Commented May 4, 2022 at 20:56

2 Answers 2

2

You can detect overflow, or more precisely wrap around, by comparing the value with a computed maximum before the operation:

#include <stdio.h>
#include <stdint.h>

uint64_t collatz(uint64_t n) {
    uint64_t count = 0;

    if (n == 0) {
        return count;
    }

    while (n != 1) {
        if (n % 2 == 0) {
            n /= 2;
        } else {
            if (n > (UINT64_MAX - 1) / 3) {
                printf("overflow!\n");
                return UINT64_MAX;
            }
            n = (3 * n) + 1;
        }
        if (count == UINT64_MAX) {
            printf("too many iterations!\n");
            return UINT64_MAX;
        }
        count++;
    }
    return count;
}
Sign up to request clarification or add additional context in comments.

4 Comments

Since the function can legitimately return 0, would return 0; --> return UINT64_MAX; be better as an overflow sentinel value?
@CraigEstey: good point. If count can reach UINT64_MAX, it seems obvious that n must be part of a cycle that does not include 1, hence UINT64_MAX cannot be a legitimate result for a uint64_t argument.
why have you done (UINT64_MAX - 1) / 3 to detect overflow? @chqrlie
@angelina: because if n = (UINT64_MAX - 1) / 3, the computation will not overflow as the new value will be UINT64_MAX, UINT64_MAX-1 or UINT64_MAX-2, and the next value of n will produce UINT64_MAX+1, UINT64_MAX+2 or UINT64_MAX+3, hence an overflow. Using the exact values, n = 0x5555555555555554, 3 * n + 1 = 18446744073709551613, which is UINT64_MAX-2 and the next value produces UINT64_MAX+1 which wraps around to 0.
2

The expression n /= 2; should never overflow, so I'm not worried about that.

The question I think you're asking is:

Will n = (3 * n) + 1; ever overflow?

That can be answered as an inequality:

  • If (3 * n) + 1 > UINT64_MAX, then you have Overflow.

And that is an inequality you can solve algebraically.

  • If (3*n) > UINT64_MAX-1, then you have Overflow
  • If n > (UINT64_MAX-1)/3, then you have Overflow

So, ultimately, if n > (UINT64_MAX-1)/3 (or approximately 6.1489e18), then you cannot complete the calculation without overflowing uint64_t.

1 Comment

You arrived at the right result, but it's risky to try to apply algebra to C code, since integer division acts differently than division in your math classes. (Algebra tells us that if n/10 = 0 then n = 0.) You can apply one definition/property of unsigned integer division, which is that A/B is the largest integer such that (A/B) * B does not exceed B.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.