C++ Development Basics: Why Subtracting Two unsigned __int64 Values Does Not Yield the Expected Result?

C++ Development Basics: Why Subtracting Two unsigned __int64 Values Does Not Yield the Expected Result?

Introduction

In daily C++ development, especially when dealing with data that requires a large range of values, such as timestamps and counters, we often use <span>unsigned __int64</span> (also known as <span>uint64_t</span> in the standard library). However, many people may be surprised by the result when they first encounter its subtraction operation.

Let’s look at an example:

#include <iostream>

int main() {
    unsigned __int64 a = 134001416236650000;
    unsigned __int64 b = 134001416237150000;

    auto diff = a - b;

    std::cout << "a - b = " << diff << std::endl;
    return 0;
}

Program output:

a - b = 18446744073709051616

However, the expected mathematical result should be:

134001416236650000 - 134001416237150000 = -500000

Why is there such a large discrepancy?

1. Rules of Unsigned Integer Operations

The C++ standard specifies:

  • All unsigned integer operations are performed modulo (mod 2^N).
  • • For <span>unsigned __int64</span>, N = 64, so it is mod 2^64.

In other words, <span>unsigned __int64</span> does not represent negative numbers, and all operation results must fall within the range of <span>0 ~ 2^64 - 1</span>.

When <span>a < b</span>, the mathematical result is negative, but <span>unsigned __int64</span> cannot accommodate it, so it wraps around:

a - b = (2^64) - 500000
      = 18446744073709551616 - 500000
      = 18446744073709051616

This is the “huge value” you see.

C++ Development Basics: Why Subtracting Two unsigned __int64 Values Does Not Yield the Expected Result?

2. Incorrect Example: Naively Subtracting Unsigned Values

Many developers directly subtract when calculating time differences:

unsigned __int64 start = getTimestamp();
unsigned __int64 end   = getTimestamp();

unsigned __int64 diff = end - start;

If <span>end < start</span> (for example, if the timer resets or crosses an overflow boundary), the result will be completely incorrect.

3. Correct Solutions

It depends on your requirements:

✅ Requirement 1: Want the absolute difference

unsigned __int64 diff = (a > b) ? (a - b) : (b - a);
std::cout << "Absolute diff = " << diff << std::endl;

Output:

Absolute diff = 500000

✅ Requirement 2: Want a signed difference (can represent positive and negative)

__int64 diff = static_cast<__int64>(a) - static_cast<__int64>(b);
std::cout << "Signed diff = " << diff << std::endl;

Output:

Signed diff = -500000

✅ Requirement 3: Timestamp difference function

If you are handling timestamp differences (e.g., microsecond/millisecond level differences), it is recommended to encapsulate a function:

__int64 TimestampDiffMicroSec(unsigned __int64 t1, unsigned __int64 t2) {
    return static_cast<__int64>(t1) - static_cast<__int64>(t2);
}

__int64 TimestampDiffMilliSec(unsigned __int64 t1, unsigned __int64 t2) {
    return (static_cast<__int64>(t1) - static_cast<__int64>(t2)) / 1000;
}

This way, regardless of whether <span>t1</span> is larger or <span>t2</span> is larger, you can obtain the correct signed difference.

4. Best Practices

  1. 1. Do not directly perform subtraction on unsigned integers, otherwise, if the order is reversed, the result will wrap around to near 2^64.
  2. 2. Clarify requirements:
  • • If you only need the magnitude of the difference → use the absolute value.
  • • If you need the direction of the difference (the order) → use signed integers.
  • 3. Write utility functions to avoid repeating pitfalls in the project.
  • Conclusion

    The reason why subtracting two <span>unsigned __int64</span> values does not yield the expected result is not due to a bug in C++, but because the rules of unsigned number operations are modulo 2^64. Negative results under <span>unsigned __int64</span><code><span> will be "wrapped around" to a very large number. The solutions are: for absolute difference → </span><code><span>(a > b) ? (a - b) : (b - a)</span>; for signed difference → convert to <span>__int64</span> and then calculate.

    If this article has been helpful to you, I would be very honored.

    If you have any other opinions on this article, feel free to leave a comment for discussion.

    If you like my articles, thank you for the triple support: like, follow, and share!!!

    Leave a Comment