1. 程式人生 > >【轉】如何用 C/C++ 求 1 到 1000 內的所有完全數

【轉】如何用 C/C++ 求 1 到 1000 內的所有完全數

這是個小題目,按定義窮舉算是基本的練習,並太多特別值得說的地方。選個合適的語言,也就是一兩行程式碼按定義表示出來,比如 Python:
[n for n in range(1, 1000)
    if sum(k for k in range(1, n) if n%k == 0) == n]
另一方面這又是個數學題目。可以想見會有人想出一些辦法去做「優化」,卻輕視程式設計碼程式碼之前的數學與演算法上的分析。實際上,如果未經深思熟慮,這類優化能起到的效果甚微,在本質上不能減少多少運算。因此,倒不如仔細從數學角度好好看看這個問題,給出一個完全不一樣的演算法,或許會讓這個原本不起眼的小題目吃起來更有嚼頭一些。

---

Euclid-Euler 定理,一個數 n 是偶完全數,當且僅當n = 2^{k-1} (2^k - 1),其中 2^k - 1 是一個梅森素數

奇完全數是否存在,是當今數論中未解決的問題。但
已有文獻指出
,奇完全數即使存在,則不小於 10^{1500},因此在合理範圍內無須考慮。

於是現在問題歸結到求一組較小的 k 使 2^k -1 是梅森素數,然後套用 Euclid-Euler 定理公式計算。

驗證梅森素數的方法,較為有效的是 Lucas–Lehmer 檢驗法。即定義
s_k = \begin{cases}4, & k = 0, \\s_{k-1}^2 - 2, & k > 0.\end{cases}
從而 M_k = 2^k - 1 是素數當且僅當
s_{k-2} \equiv 0 \pmod {M_k}
其中 k 是奇數,由梅森素數的性質,等價於 k 是奇素數。k 為偶數 2 則是特殊情形,M_2 = 3 是素數。

為方便計算,事實上並不需要求出所有的 s_k,只要求得餘數即可(否則中間結果會很大)。而這個條件用計算機非常容易驗證。

由於只要求 1000 以內的完全數,因此用 n 的表示式粗略地估計,最多隻要求出 1000 以內的梅森素數。注意到 2 的 10 次方即超出 1000,因此只需要考慮 k 小於 10 的情形進行驗證。因此這也是很有效的演算法,遠好於用定義試除計算。

下面是程式碼:
#include <iostream>
inline long mersenne(int k) { return (1L << k) - 1L; } // euclid_euler(k) is perfect if mersenne(k) is prime // http://en.wikipedia.org/wiki/Euclid%E2%80%93Euler_theorem inline long euclid_euler(int k) { return ((1L<<k) - 1L) << (k-1); } // return true if mersenne(k) is prime bool lucas_lehmer_test
(int k) { // special case: merssene(2) = 3 is prime if (k <= 2) return k == 2; // Lucas-Lehmer test // http://mathworld.wolfram.com/Lucas-LehmerTest.html long s = 4; long m = mersenne(k); for (int i = 0; i < k - 2; ++i) { s = s * s - 2; if (m != 0) s %= m; } return s == 0; } int main() { const long perfect_number_bound = 1000; for (int k = 0; euclid_euler(k) < perfect_number_bound; ++k) { if (lucas_lehmer_test(k)) std::cout << euclid_euler(k) << '\n'; } return 0; } // Result: // 6 // 28 // 496

相關推薦

1~1000之間的全數

#include<iostream.h> void main() { int a,b,sum=0; for(a=6;a<1000;a++) { for(b=1;b<a;

如何用 C/C++ 11000 所有全數

這是個小題目,按定義窮舉算是基本的練習,並太多特別值得說的地方。選個合適的語言,也就是一兩行程式碼按定義表示出來,比如 Python: [n for n in range(1, 1000) if sum(k for k in range(1, n) if n%k == 0) == n] 另一方面

Coding篩法素數的C++實現(附100000以內素數表)

#include <cstdio> #include <cstring> using namespace std; #define MAXN 1000000+100 bool arr[MAXN]; void findPrime(int

VS2010中 C++創建DLL圖解

-a rar cls ret ria endif -s pan 項目 標簽: dllc++2010threadlibraryc 本文章已收錄於: .embody { padding: 10px 10px 10px; margin: 0 -20px; b

幾種C/C++開發的開源搜尋引擎

(1)CLucene CLucene是Lucene的一個C++埠,Lucene是一個基於java的高效能的全文搜尋引擎。CLucene因為使用C++編寫,所以理論上要比lucene快。 (2)Xapian Xapian是一個用C++編寫的全文檢索程式,他的作用類似於Java的lucene。儘管在Java世

深入理解C++的動態繫結和靜態繫結

為了支援c++的多型性,才用了動態繫結和靜態繫結。理解他們的區別有助於更好的理解多型性,以及在程式設計的過程中避免犯錯誤。 需要理解四個名詞: 1、物件的靜態型別:物件在宣告時採用的型別。是在編譯期確定的。 2、物件的動態型別:目前所指物件的型別。是在執行期決定的。物件的

BlazeMeter錄制JMeter測試腳本

打開 測試的 文件 wid mbo 自己的 .net 一個 tar 工具: 1,JMeter 2,Chrome 3,BlazeMeter 4,SwitchyOmega(如果需要代理) 步驟: 以上工具準備好以後就可以錄制JMeter的測試腳本了, 在Chrome中點擊B

Python建立最簡單的web服務器

web服務 localhost 服務器 pos 根目錄 cal body -m -- 利用Python自帶的包可以建立簡單的web服務器。在DOS裏cd到準備做服務器根目錄的路徑下,輸入命令: python -m Web服務器模塊 [端口號,默認8000]

宏定義代替printf函數

tar 版本 data eas article target else define ref 問題提出 有時候我們想用宏定義來決定是編譯debug版本的代碼還是release的代碼,dubug版本的代碼會通過printf打印調試信息,release版本的代碼則不會。我們總不

python比對數據庫表數據的腳本

%s import gpa post parse pwd 基本原理 -- get 最近在做一個數據庫異構復制的項目,客戶表示需要一個數據比對的工具,我就自己寫了一個異構數據庫的比對python腳本.這個比對腳本只能比對數量,不能比對具體的記錄.使用的sql語句也是最基礎的s

Java實現網路語音訊號傳送

本文轉載自部落格:https://www.aliyun.com/jiaocheng/347518.html ----------------------------------------------------------------------------------------------

jsmin批量壓縮JS的批處理檔案

在網頁中動態載入的 JavaScript 對於頁面顯示的速度影響甚多,不得不注意! 尤其是很多人習慣把 JavaScript include 寫在 <head> 區塊中,這樣一來最大的問題就是 Browser 必須要等到 JavaScript 全部讀完後才會開始顯

通俗易懂的話說下hadoop是什麼,能做什麼

轉自http://blog.csdn.net/houbin0912/article/details/72967178hadoop是什麼?(1)Hadoop是一個開源的框架,可編寫和執行分散式應用處理大規模資料,是專為離線和大規模資料分析而設計的,並不適合那種對幾個記錄隨機讀寫

opencv使攝像頭在30fps下捕獲1080p的數據

idt apt 壓縮 .com ont blog 設置 幀率 rop 原文:http://blog.sina.com.cn/s/blog_9b493e7b0102xvn6.html opencv可以捕獲攝像頭數據。如果要讀高分辨率和高幀率,可以用如下的設置: captu

CSS塊級元素和行元素

http://www.studyofnet.com/news/398.html 本文導讀:HTML中的元素可分為兩種型別:塊級元素和行級元素。這些元素的型別是通過文件型別定義(DTD)來指明。塊級元素:顯示在一塊內,會自動換行,元素會從上到下垂直排列,各自佔一行,如p,ul,

1到10000的全數

function  wanquanshu() { for(var i=1;i<10000;i++) {  var sum=0;  for(var j=1;j<i;j++)  {   if(

1-1000所有質數

質數也稱素數,即因子數只有1和其自身,不要和奇數混淆(奇數是不能被2整除的數)! void PrimeNumber() { for (int i = 1; i <= 1000; ++i) { int count = 0, num = 1;//

一個數如果恰好等於它的因子之和(包括1,但不包括這個數本身),這個數就稱為“數,1-1000中的

/*問題分析:問題中不是要質因數,所以找到的因數後就無需將其從資料中“除掉”。每個因數只記一次如:8的因數為1,2,4而不是1,2,2,2,4*/#include<stdio.h>int main(){int i,k,j,s,a[20];for(i=1;i<

窮舉法1000所有

題目:   一個數如果恰好等於它的因子之和,這個數就稱為 "完數",   例如6=1+2+3。程式設計找出1000以內的所有完數。 思路: 窮舉法(簡直就是萬能的存在~) 程式碼: package day5; public class&nb