您发生了许多隐式转换,其中大多数是不必要的。
unsigned long long int a = 17446744073709551615;
无后缀十进制整数文字的类型为int
、long int
或long long int
; 它永远不是无符号类型。long long int
该特定值几乎肯定超过了 a (2 63 -1)的最大值。除非您的编译器具有比 64 位更宽的有符号整数类型,否则这会使您的程序格式错误。
添加ULL
后缀以确保文字的类型正确:
unsigned long long int a = 17446744073709551615ULL;
该值恰好介于 2 63 -1 和 2 64 -1 之间,因此它适合 64 位无符号类型,但不适合 64 位有符号类型。
(实际上就U
足够了,但明确一点也无妨。)
signed long long int b = -30000000003;
这应该不是问题。30000000003
是某种有符号整数类型;如果您的编译器支持long long
至少 64 位宽的 ,则不会溢出。不过,只要您需要在 的值上加上后缀,a
明确说明就没有坏处:
signed long long int b = -30000000003LL;
现在我们有:
signed int c;
c = a/b;
将 a除以unsigned long long
asigned long long
会导致有符号操作数转换为unsigned long long
。在这种情况下,被转换的值是负数,所以它被转换成一个大的正值。转换-30000000003
为unsigned long long
收益率18446744043709551613
。除以17446744073709551615
产生18446744043709551613
零。
除非您的编译器支持大于 64 位的整数(大多数不支持),否则您将无法直接除以17446744073709551615
并-30000000003
获得数学上正确的答案,因为没有整数类型可以表示这两个值。所有算术运算符(除了移位运算符)都需要相同类型的操作数,并根据需要应用隐式转换。
在这种特殊情况下,您可以除以17446744073709551615ULL
然后30000000003ULL
占符号。(检查负整数除法的语言规则。)
如果你真的需要这样做,你可以求助于浮点(这意味着你可能会失去一些精度)或使用一些任意宽度的整数算术包,如GMP。