Java 和 CPP 的不同输出

Different outputs for Java and CPP

我正在解决 Nth root of M 问题,我用 Java 解决了它,这是解决方案:

    public int NthRoot(int n, int m)
    {
        // code here
        int ans = -1;
        if (m == 0)
            return ans;
        if (n == 1 || n == 0)
            return m;
        if (m == 1)
            return 1;
        int low = 1;
        int high = m;
        while (low < high) {
            
            int mid = (low + high) / 2;
            int pow = (int)Math.pow(mid, n);
            if (pow == m) {
                
                ans = mid;
                break;
            }
            if (pow > m) {
                
                high = mid;
            } else {
                
                low = mid + 1;
            }
        }
        
        return ans;
    }

它通过了所有的测试用例。但是,当我使用 C++ 解决它时,一些测试用例没有通过。这是 C++ 解决方案:

    int NthRoot(int n, int m)
    {
        // Code here.
        int ans = -1;
        if (m == 0)
            return ans;
        if (n == 1 || n == 0)
            return m;
        if (m == 1)
            return 1;
        int low = 1;
        int high = m;
        while (low < high) {
            
            int mid = (low + high) / 2;
            int po = (int)pow(mid, n);
            if (po == m) {
                
                ans = (int)mid;
                break;
            }
            if (po > m) {
                
                high = mid;
            } else {
                
                low = mid + 1;
            }
        }
        
        return ans;
    } 

它没有通过的测试用例之一是:

6 4096
Java's output is 4 (Expected result)
C++'s output is -1 (Incorrect result)

当我用纸和笔描绘它时,我得到了与Java相同的解决方案。

但是,当我在 C++ 代码中使用 long long int 时,它工作正常——但是 Java 和 C++ 中 Int/int 的大小是一样吧? (当我在 C++ 和 Java 中打印 INT_MAXInteger.MAX_VALUE 时,它输出相同的值。)

正如您可能已经猜到的那样,问题是由于尝试将 double 值转换为 int 值时,当该源大于 [= 的最大可表示值时12=]。更具体地说,它涉及 Java 和 C++ 在 while 循环开始附近处理转换的方式的区别:int po = (int)pow(mid, n);.

对于您的示例输入 (6 4096),pow 函数在第一个 运行 循环中返回的值是 7.3787e+19,这太大了对于 int 值。在 Java 中,当您尝试将过大的值转换为整数时,结果是整数类型可表示的最大值,如 this answer 中指定(加粗我的):

  • The value must be too large (a positive value of large magnitude or positive infinity), and the result of the first step is the largest representable value of type int or long.

但是,在 C++ 中,当源值超过 INT_MAX 时,行为未定义(根据此 C++11 Draft Standard):

7.10 Floating-integral conversions      [conv.fpint]

1    A prvalue of a floating-point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.

然而,尽管形式上未定义,many/most compilers/platforms 将在发生这种情况时应用 'rollover',从而导致非常大的 负数 值(通常,INT_MIN) 作为结果。这就是 Visual Studio 中的 MSVC 所做的,给出 -2147483648 的值,从而导致 else 块变为 运行 … 并且 keep 运行ning 直到 while 循环达到其终止条件——此时 ans 将永远不会被分配任何值,除了初始 -1.

您可以通过检查 pow 调用返回的 double 并将 po 设置为 INT_MAX(如果合适)来模拟 Java 行为:

    while (low < high) {
        int mid = (low + high) / 2;
        double fpo = pow(mid, n);
        int po = (int)(fpo);
        if (fpo > INT_MAX) po = INT_MAX; // Emulate Java for overflow
        if (po == m) {
            ans = (int)mid;
            break;
        }
        if (po > m) {
            high = mid;
        }
        else {
            low = mid + 1;
        }
    }