繁体   English   中英

为什么这个长溢出为-1,而不是类型的最小值?

[英]Why is this long overflowing to -1, instead of the minimum value for the type?

我有以下的代码,返回时完全二叉树是树的节点数目layer的层身材:

public static long nNodesUpToLayer(int layer) {
        if (layer < 0) throw new IllegalArgumentException(
            "The layer number must be positive: " + layer );

        //At layer 0, there must be 1 node; the root.
        if (layer == 0) return 1;

        //Else, there will be 1 + 2 * (the number of nodes in the previous layer) nodes.
        return 1 + (2 * nNodesUpToLayer(layer - 1));

奇怪的是,当我在函数中输入63 (产生这个的最小值)时,它会让我回到-1 62 ,它返回9223372036854775807 ,所以这似乎是由溢出引起的。

它不应该让我回到Java长期的最小值+它溢出的数量吗? 无论我给它的输入(通过62 ),它总是会返回-1而不是一个看起来随机的数字,我期望从溢出。

我不完全确定如何调试它,因为它是递归的,并且只有在函数达到基本情况时才会评估我感兴趣的值。

你是对的,它是64位有符号整数的溢出错误。 它变为-1而不是最小整数值的原因是因为你加倍,而不是简单地添加一个。

Two's Complement中的 9223372036854775807是63 1 s:

0111 1111 ... 1111 1111

要以二进制加倍,只需执行左移:

1111 1111 ... 1111 1110

但是,Two's Complement中的这个数字不是两倍9223372036854775807 ,而是-2 然后,当然,在返回获得-1结果之前,先添加1

实际上,它会返回正确的金额。 它只是“它溢出的数量”是完全正确的答案-1 :)

考虑一下:
对于n层,完整二叉树中的节点数为2^n - 1 因此,它的二进制表示为0000...00111...111 ,其中数量1 s是精确的层数减1。一旦你到达的长度long你被困在被截断的11...11 ,正好是-1

我总是喜欢用这样的东西进行可视化。

                      (min long)
                      v 
<--------------------||--------------------------------------->
                     ^                                   ^
               (max long, n)                            -1

其中n是9223372036854775807 - 在乘以2之前的值。而不是乘法,而是将其视为加法。 n + n 通过在数字线上看到它,你可以看到你最终在-2。 你基本上已经超过了大多数负数。

因此,与其他人相比,我的答案提供了一些有意义的东西,在这种情况下,一个有用的工具是将算术分成多行以便进行调试。 你可以写:

int a = nNodesUpToLayer(layer - 1);
int b = 2 * a;
int c = 1 + b;
return c;

您实际上正在按照您的预期强制执行操作顺序(这可能会帮助您实现程序按照您希望的顺序执行操作),但它也允许您进入调试器并查看中间程序你的计算值。 在这里你会注意到b == -2 为什么b == -2 好吧,一定是因为2 * a == -2等。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM