【问题标题】:Determining if square root is an integer确定平方根是否为整数
【发布时间】:2014-04-09 22:50:03
【问题描述】:

在我的程序中,我试图找出数字 600851475143 的最大素数。我制作了一个 for 循环来确定该数字的所有因数并将它们存储在向量数组中。我遇到的问题是我不知道如何确定该因子是否可以平方根并给出整数而不是小数。到目前为止,我的代码是:

#include <iostream>
#include <vector>
#include <math.h>

using namespace std;
vector <int> factors;

int main()
{
    double num = 600851475143;
    for (int i=1; i<=num; i++)
    {
        if (fmod(num,i)==0)
        {
            factors.push_back(i);
        }
    }

     for (int i=0; i<factors.size(); i++)
     {
         if (sqrt(factor[i]))                      // ??? 
     }
}

有人可以告诉我如何通过我的 if 语句确定一个数字是否可以平方根吗?

【问题讨论】:

标签: c++ arrays loops math sqrt


【解决方案1】:

由于 sqrt() 函数使用浮点数,最好避免使用它的返回值(浮点数计算有时会因为精度错误而给出错误结果 em>)。相反,您可以编写一个函数 - isSquareNumber(int n),它将决定数字是否为平方数,并且整个计算将以整数完成。

bool isSquareNumber(int n){
    int l=1, h=n;
    while(l<=h){
        int m = (l+h) / 2;
        if(m*m == n){
            return true;
        }else if(m*m > n){
            h = m-1;
        }else{
            l = m+1;
        }
    }
    return false;
}

int main()
{
   // ......
     for (int i=0; i<factors.size(); i++){
         if (isSquareNumber(factor[i]) == true){
              /// code
         }
     }
}

【讨论】:

    【解决方案2】:

    这是我编写的一个简单的 C++ 函数,用于确定数字是否具有整数平方根:

    bool has_sqrtroot(int n)
    {
        double sqrtroot=sqrt(n);
        double flr=floor(sqrtroot);
        if(abs(sqrtroot - flr) <= 1e-9)
            return true;
    
        return false;
    }
    

    【讨论】:

      【解决方案3】:

      你问错问题了。你的算法是错误的。 (嗯,不完全,但如果要按照提出的想法进行纠正,那将是非常低效的。)使用您的方法,您还需要递归地检查立方、五次方和所有其他素数。例如,尝试找出 5120=5*2^10 的所有因数。


      更简单的方法是通过除法找到一个因子后删除它

      num=num/i
      

      并且只有当它不再是一个因素时才增加 i。然后,如果迭代遇到一些 i=j^2 或 i=j^3,... ,则所有因素 j(如果有)已经在早期阶段被删除,当时 i 具有值 j,并在因子数组。


      您也可以提到这是来自 Euler 项目,问题 3。那么您可能会发现最近的讨论“advice on how to make my algorithm faster”,其中讨论了更有效的分解算法变体。

      【讨论】:

        【解决方案4】:

        以下应该有效。它利用整数截断。

        if (int (sqrt(factor[i])) * int (sqrt(factor[i])) == factor[i])
        

        之所以有效,是因为非平方数的平方根是小数。通过转换为整数,您可以删除双精度的小数部分。一旦你把它平方,它就不再等于原来的平方根了。

        【讨论】:

        • 我不认为“十进制”是正确的词,因为我们不是在谈论字符串。
        • 谢谢。虽然小数部分是有道理的,但这不是正确的说法。我必须查一下小数点前后的数字叫什么。显然,一种被接受的方法是小数部分。找到答案here
        【解决方案5】:

        完全平方只能以 16 为底以 0、1、4 或 9 结尾,因此对于 75% 的输入(假设它们是均匀分布的),您可以避免调用平方根以换取一些非常快的有点玩弄。

        int isPerfectSquare(int n)
        {
            int h = n & 0xF;  // h is the last hex "digit"
            if (h > 9)
                return 0;
            // Use lazy evaluation to jump out of the if statement as soon as possible
            if (h != 2 && h != 3 && h != 5 && h != 6 && h != 7 && h != 8)
            {
                int t = (int) floor( sqrt((double) n) + 0.5 );
                return t*t == n;
            }
            return 0;
        }
        

        用法:

        for ( int i = 0; i < factors.size(); i++) {
           if ( isPerfectSquare( factor[ i]))
             //...
        }
        

        Fastest way to determine if an integer's square root is an integer

        【讨论】:

        • if ((((1&lt;&lt;0)|(1&lt;&lt;1)|(1&lt;&lt;4)|(1&lt;&lt;9)) &amp; (1 &lt;&lt; (n &amp; 15)))!=0) ...
        【解决方案6】:
        int s = sqrt(factor[i]);
        if ((s * s) == factor[i]) 
        

        正如霍布斯在 cmets 中指出的那样,

        假设 double 是通常的 64 位 IEEE-754 双精度浮点数,对于小于 2^53 的值,一个 double 和下一个可表示的 double 之间的差小于或等于 1。高于 2^53,精度比整数差。

        因此,如果您的 int 是 32 位,那么您是安全的。如果你必须处理大于 2^53 的数字,你可能会遇到一些精度错误。

        【讨论】:

        • 是的。这应该适用于 factor[i] 最多 2^53 左右。
        • 是的,因为 factor 是 int 的向量,所以我们是安全的。
        • 好吧,就我们所知,int 可能是 64 位的。 :)
        • 但是我想你的 2^53 限制也会提高。顺便说一句,你从哪里弄来的?
        • 假设 double 是通常的 64 位 IEEE-754 双精度浮点数,对于小于 2^53 的值,一个 double 和下一个可表示的 double 之间的差异较小大于等于1。2^53以上,精度比整数差。
        【解决方案7】:

        与 cero 进行比较时,您还必须考虑舍入误差。如果你的编译器支持c++11,你可以使用std::round,如果不支持,你可以自己做(here)

        #include <iostream>
        #include <vector>
        #include <math.h>
        
        using namespace std;
        vector <int> factors;
        
        int main()
        {
            double num = 600851475143;
            for (int i=1; i<=num; i++)
            {
                if (round(fmod(num,i))==0)
                {
                    factors.push_back(i);
                }
            }
        
             for (int i=0; i<factors.size(); i++)
             {
                 int s = sqrt(factor[i]);
                 if ((s * s) == factor[i])  
             }
        }
        

        【讨论】:

          猜你喜欢
          • 2010-09-22
          • 2015-08-11
          • 1970-01-01
          • 2012-02-13
          • 2011-08-14
          • 1970-01-01
          • 1970-01-01
          • 2016-04-27
          相关资源
          最近更新 更多