简体   繁体   English

Java 和 CPP 的不同输出

[英]Different outputs for Java and CPP

I was solving Nth root of M problem and I solved it with Java and here is the solution:我正在解决M问题的第 N 个根,我用 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;
    }

It passed all the test cases.它通过了所有的测试用例。 But, when I solved it using C++, some test cases didn't pass.但是,当我使用 C++ 解决它时,一些测试用例没有通过。 Here is the C++ solution:这是 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;
    } 

One of the test cases it didn't pass is:它没有通过的测试用例之一是:

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

When I traced it using paper and pen, I got a solution the same as Java's.当我用纸和笔追踪它时,我得到了一个与 Java 相同的解决方案。

But, when I used long long int in the C++ code, it worked fine – but the size of Int / int in both Java and C++ are the same, right?但是,当我在 C++ 代码中使用long long int时,它工作得很好——但是 Java 和 C++ 中Int / int的大小是一样的,对吧? (When I print INT_MAX and Integer.MAX_VALUE in C++ and Java, it outputs the same value.) (当我在 C++ 和 Java 中打印INT_MAXInteger.MAX_VALUE时,它输出相同的值。)

As you have probably guessed, the problem is due to the attempt to convert a double value to an int value, when that source is larger than the maximum representable value of an int .正如您可能已经猜到的,问题是由于尝试将double值转换为int值,当该源大于int的最大可表示值时。 More specifically, it relates to the difference between how Java and C++ handle the cast near the start of your while loop: int po = (int)pow(mid, n);更具体地说,它与 Java 和 C++ 在while循环开始附近处理强制转换的方式之间的差异有关: int po = (int)pow(mid, n); . .

For your example input ( 6 4096 ), the value returned by the pow function on the first run through that loop is 7.3787e+19 , which is too big for an int value.对于您的示例输入 ( 6 4096 ), pow函数在第一次运行该循环时返回的值是7.3787e+19 ,这对于int值来说太大了。 In Java, when you attempt to cast a too-big value to an integer, the result is the maximum value representable by the integer type, as specified in this answer (bolding mine):在 Java 中,当您尝试将太大的值转换为整数时,结果是整数类型可表示的最大值,如本答案(我的粗体)中所述:

  • 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 .该值必须太大(大的正值或正无穷大),并且第一步的结果是 int 或 long 类型的最大可表示值

However, in C++, when the source value exceeds INT_MAX , the behaviour is undefined (according to this C++11 Draft Standard ):但是,在 C++ 中,当源值超过INT_MAX ,行为未定义(根据此C++11 草案标准):

7.10 Floating-integral conversions [conv.fpint] 7.10 浮点积分转换 [conv.fpint]

1 A prvalue of a floating-point type can be converted to a prvalue of an integer type. 1浮点类型的纯右值可以转换为整数类型的纯右值。 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.如果截断的值无法在目标类型中表示,则行为未定义。

However, although formally undefined, many/most compilers/platforms will apply 'rollover' when this occurs, resulting in a very large negative value (typically, INT_MIN ) for the result.然而,虽然正式未定义,但许多/大多数编译器/平台在发生这种情况时会应用“翻转”,从而导致结果的负值非常大(通常为INT_MIN )。 This is what MSVC in Visual Studio does, giving a value of -2147483648 , thus causing the else block to run … and keep running until the while loop reaches its terminating condition – at which point ans will never have been assigned any value except the initial -1 .这就是 Visual Studio 中的 MSVC 所做的,给出值-2147483648 ,从而导致else块运行……并继续运行直到while循环达到其终止条件——此时ans将永远不会被分配任何值,除了初始值-1

You can fix the problem readily by checking the double returned by the pow call and setting po to INT_MAX , if appropriate, to emulate the Java bevahiour:您可以通过检查pow调用返回的double INT_MAX并将po设置为INT_MAXINT_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;
        }
    }

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

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