Java之判斷大整數是否為平方數


  在本篇博客中,我們將討論如何使用有效的算法來判斷一個大整數是否為平方數。
  給定正整數\(n\),如果存在一個整數\(m\),滿足\(m^{2}=n\),那么則稱\(n\)為平方數。因此,判斷一個大整數\(n\)是否為平方數,很自然的想法就是,從1開始,依次遞增,判斷這個數的平方是否等於給定的數\(n\),如果是,則\(n\)為平方數,如果這個數的平方大於\(n\),則\(n\)不是平方數。這個想法很簡單,但可惜的是,效率卻很低,因為我們要遍歷\(\sqrt{n}\)個數,當\(n\)很大時,這樣的效率是我們不能忍受的。
  那么有沒有其他方法呢?這時候,一個公式進入我們的視野,那就是:

\[1+3+5+...+2n-1=n^{2}. \]

看上去這個公式給了我們一點希望,因為我們不需要從1開始一個一個去找,而是只需要尋找至\(2\sqrt{n}-1\)即可。但我們仔細地分析一下,不難發現,該公式的實質和一個一個找沒什么區別,因為我們還是要遍歷\(\sqrt{n}\)個數。
  所以,存在有效的算法嗎?答案是肯定的!為什么不嘗試着去計算\(n\)的平方根呢?按照這個思路,我們具體的算法,結合牛頓法,步驟如下:

  1. 初始值\(x_0=1\), 誤差\(\epsilon\)足夠小;
  2. 按照\(x_{n+1}=\frac{1}{2}(x_{n}+\frac{n}{x_{n}})\)迭代,直至\(|x_{n}^{2}-n|\leq\epsilon\);
  3. \(x_{n}\)取整,結果為\(m\), 如果\(m\)的平方為\(n\),則\(n\)為平方數,否則不是平方數。

  接下來,我們證明這個算法的有效性。首先,我們證明對於\(n\geq1\),都有\(x_{n} > \sqrt{n}\)。我們使用數學歸納法。

  1. \(n=1\)時,\(x_{1}=\frac{1}{2}(1+n)>\sqrt{n}\).
  2. 假設\(x_{n}>\sqrt{n}\),則\(x_{n+1}-\sqrt{n}=\frac{x_{n}^{2}+n-2\sqrt{n}x_{n}}{2x_{n}}=\frac{(x_{n}-\sqrt{n})^{2}}{2x_{n}}>0\),所以\(x_{n+1}>\sqrt{n}\).

接着我們再證明\(x_{n}(n\geq1)\)序列遞減。因為當\(n>0\)時,有

\[x_{n+1}-x_{n}=\frac{n-x_{n}^{2}}{2x_{n}}<0. \]

這是因為當\(n\geq1\)時,有\(x_{n}>\sqrt{n}\).

  因此,我們利用第二步的迭代,不停地運算后,所得到的項\(x_{n}\)\(\sqrt{n}\)很接近,只是稍微大一點。因此,該算法的第三步的判斷就是正確的了。
  下面我們將會給出上述算法的Java程序代碼,具體如下:

package Problems;

import java.math.BigInteger;
import java.math.BigDecimal;

public class IS_Square {
    public static void main(String[] args) {

        // 計算2**128+1
        BigInteger F7 = new BigInteger("2").pow(128).add(BigInteger.ONE);
        boolean w = is_square(F7);
        if(w)
            System.out.println(String.format("%s是完全平方數。", F7));
        else
            System.out.println(String.format("%s不是完全平方數。", F7));

    }

    // 判斷是否為完全平方數
    public static boolean is_square(BigInteger F7){
        // 牛頓法求解平方根, 求解a的平方根
        // x為a的平方根,x的初始值為1, 按x = (x+a/x)/2迭代, 誤差為error
        BigDecimal x = BigDecimal.ONE;
        BigDecimal a = new BigDecimal(F7.toString());
        BigDecimal eps = new BigDecimal("1");
        final BigDecimal error = new BigDecimal("1E-10");
        int scale = 100;

        // 進入循環
        while(eps.compareTo(error) == 1){ // eps > error
            x = x.add(a.divide(x, scale, BigDecimal.ROUND_HALF_UP)).divide(new BigDecimal("2.0"), scale, BigDecimal.ROUND_HALF_UP);
            eps = x.multiply(x).subtract(a).abs();
        }

        BigInteger sqrt = x.toBigInteger();  // 求平方根的整數部分
        if(sqrt.pow(2).compareTo(F7) == 0)
            return true;
        else
            return false;

    }

}

其輸出結果如下:

340282366920938463463374607431768211457不是完全平方數。

如果將Java程序中的\(F7=2^{128}\),則輸出結果為:

340282366920938463463374607431768211456是完全平方數。

  本次分享到此結束,歡迎大家交流~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM