Checking if a number is perfect square?

后端 未结 8 2027
野趣味
野趣味 2021-02-10 01:10

I think there is a precision problem with the following code:

bool isPerfectSquare(long long n){
    long long squareRootN=(long long)(sqrt(n)+0.5);

    return          


        
8条回答
  •  我在风中等你
    2021-02-10 01:39

    Sqrt(4) could return 1.9999

    No, 4 and 2 are exactly representable as binary floating point numbers. No precision problems there.

    The problem is that long long has 64 bits of precision, but double has only 52, so all solutions that rely on calling sqrt(double) will start failing when you hit that limit. Here is a simple test program:

    #include 
    #include 
    #include 
    
    bool isPerfectSquare(long long n)
    {
        double root = sqrt(n);
        return floor(root) == root;
    }
    
    void check(long long x)
    {
        if (!isPerfectSquare(x))
            std::cerr << x << " should be perfect\n", exit(1);
        if (isPerfectSquare(x-1))
            std::cerr << x-1 << " should NOT be perfect\n", exit(1);
        if (isPerfectSquare(x+1))
            std::cerr << x+1 << " should NOT be perfect\n", exit(1);
    }
    
    int main()
    {
        for (long long i = 2; i < 3037000499; ++i)
            check(i * i);
        std::cout << "all tests passed\n";
    }
    

    And here is the output on my computer:

    4503599627370497 should NOT be perfect
    

    Note that log(4503599627370497)/log(2) = 52. In case you don't care about numbers that large, you can use the simple solution that merely checks whether sqrt returns an integral result.

提交回复
热议问题