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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.