跳至主要内容

求完美数

求完美数

redraiment, 2008-07-10





  一个数如果恰好等于它的因子之和,这个数就称为“完美数”或“完数”,例如 6=1+2+3(6的因子是1,2,3)。完美数的一些性质:
    1. 欧几里德证明了:一个偶数是完数,当且仅当它具有如下形式:2(p-1)×(2p-1) 其中 p 和 2p-1 是素数。尽管没有发现奇完数,但是当代数学家奥斯丁·欧尔(Oystein Ore)证明,若有奇完全数,则其形状必然是 12p+1 或 36p+9 的形式,其中 p 是素数。在 1018 以下的自然数中奇完数是不存在的。
    2. 除 6 以外的偶完数,把它的各位数字相加,直到变成一位数,那么这个一位数一定是 1(亦即:除6以外的完数,被9除都余1) 28:2+8=10,1+0=1 496:4+9+6=19,1+9=10,1+0=1
    3. 因为 2p 是 2 的幂,用C语言也就是 1 << p,那么 2p-1 的二进制也就是 p 个 1 组成了,而 2(p-1) 是 2的幂,这两个数相乘,也就相当于把 2p-1 向左移 p-1 位,即 (2p-1) << (p-1),那所有完美数的二进制就是前面 p 个 1,后面跟着 p-1 个 0。 所以偶完数都可以表达为 2 的一些连续正整数次幂之和,如:
      6 = 2+ 22; 28 = 22 + 23 + 24; 8128 = 26 + 27 + ... + 212; 33550336 = 212 + 213 + ... + 224
      j = ((1 + (i ^ (i-1) )) >> 1) + i - 1;
      (j & (j + 1)) || (i & 1)
    4. 上面的代码可以判断整数 i 是否是前面 1 后面 0 的形式。
    5. 每一个偶完数都可以写成连续自然数之和: 6=1+2+3; 28=1+2+3+4+5+6+7; 496=1+2+3+…+30+31
    6. 除6以外的偶完数,还可以表示成连续奇数的立方和(被加的项共有): 28 = 13 + 33; 496 = 13 + 33 + 53 + 73; 8128 = 13 + 33 + 53 + ... + 153; 33550336 = 13 + 33 + 53 + ... + 1253 + 1273
    7. 每一个完数的所有约数(包括本身)的倒数之和,都等于2: 1/1 + 1/2 + 1/3 + 1/6 = 2; 1/1 + 1/2 + 1/4 + 1/7 + 1/14 + 1/28 = 2
  了解了上面一些性质后,就可以简单的来写一个求完美数的程序了。
#include <stdio.h>

#ifndef WIN32
typedef long long ll;
#else
typedef __int64 ll;
#endif

int main(void)
{
    ll i, j, n, x;

    for (n = 2; n <= 31; n++)
    {
        x = (1 << n) - 1;
        for(i = 3; i*i <= x; i += 2)
            if(x % i == 0)
                break;
        if(i*i <= x) continue;
        printf("%lld\n", (1 << (n - 1)) * x);
    }

    return 0;
}

  运行结果:
6
28
496
8128
33550336
8589869056
137438691328
2305843008139952128
  到目前为止,已经求出的2p-1是素数的有25个:2、3、5、7、13、17、19、31、61、89、107、127、521、607、1279、2203、2281、3217、4253、4423、9689、9941、11213、19937、21701。 据说最后一个即221701-1是1978年两名美国大学生新发现的截止目前为止最大的一个素数,所以我们可以利用这个结果来求已知的完美数:
import java.math.BigInteger;

public class Main
{
    public static void main(String[] argv)
    {
        int [] prime = {
            2,3,5,7,13,17,19,31,61,89,107,127,
            521,607,1279,2203,2281,3217,4253,
            4423,9689,9941,11213,19937,21701
        };
        BigInteger x = BigInteger.ONE;
        for (int i = 0; i < prime.length; i++)
            System.out.println ( x.shiftLeft(prime[i]-1)
                .multiply(x.shiftLeft(prime[i])
                .subtract(x)));
    }
}
  最后一个完美数的长度是13066!堪称是BinIntegest




评论

此博客中的热门博文

AutoHotKey 新手入门教程

AutoHotKey 真是一个好玩的工具!短短几行代码就是先了“窗口置顶”、“窗口透明”等功能,之前我还特意为此装了好几个小工具,现在都可以卸掉了。闲来无事,就把 Quick Start 翻译了一下,我没有逐字逐句地翻译,有时候我嫌原文罗嗦就用自己的话概括地描述了一下。 原文地址:http://www.autohotkey.com/docs/Tutorial.htm 教程目录 创建脚本 启动程序 模拟鼠标键盘 操纵窗口 输入 变量与剪切板 循环 操纵文件 其他特性 创建脚本 每个脚本都是一个纯文本文件,由一些能被 AutoHotKey.exe 执行的命令组成。一个脚本可能还包含 热键 和 热字符串 。如果没有热键和热字符串,脚本在启动的时候就会从头依次执行到尾。 创建一个新的脚本: 下载 并安装 AutoHotkey。 右击鼠标,选择 新建 -> 文本文档 。 输入文件名并确保以 .ahk 结尾。例如:Test.ahk。 右击文件,选择 编辑脚本 。 输入以下内容:#space::Run www.google.com 上一行的第一个字符 "#" 代表键盘上的 Windows 键;所以 #space 表示在按住 Windows 键后再按空格键。"::" 后面的命令会在热键激活后执行,在本例中则会打开谷歌主页。继续按下面步骤操作,来执行这个脚本: 保存并关闭该文件。 双击该文件来启动它。在系统托盘里会出现一个新图标。 按下 Windows 和空格键,网页会在默认的浏览器里打开。 右击系统托盘里的绿色图标可以退出或编辑当前脚本。 注意: 可以同时启动多个脚本,并且在系统托盘里都会有一个相应的图标。 每个脚本都能定义多个 热键 和 热字符串 。 想让某个脚本开机即启动,可以将它的 快捷方式放到开始菜单的启动目录里 。 启动程序 命令 Run 可以运行程序、打开文档、网页链接或快捷键。请参看以下示例: Run Notepad Run C:\My Documents\Address List.doc Run C:\My Documents\My Shortcut.lnk Run www.yahoo.com Run mailto:someone@somedoma

sed单行脚本学习笔记

Sed单行脚本学习笔记 redraiment, 2009-12-31 回家真好   前段时间忙着找工作、项目结题、写报告……反正是总有做不完的事情,哈哈。好在暂时告一段落了,应老妈强烈要求回家休息几天。这次回家除了这身衣服,只带了一本《 sed与awk 》,我觉得这种小册子最适合茶余饭后休闲之用。如果你也有兴趣学 sed ,推荐你一起看《 sed与awk 》(可以在 谷歌图书 在线阅读英文版:D)。   花了两天时间,看完了前面 sed 的部分。要掌握一个工具就要熟悉它的规则,man 等参考手册向我们介绍这些规则,教程则演示如何使用这些规则,但要将这些规则运用自如,还需要去理解别人的代码并尝试自己解决问题。在 SourceForge 上有份经典的文档:《 SED单行脚本快速参考 》(单行脚本要求命令行长度小于65个字符),由 Eric Pement 整理, Joe Hong 翻译,通篇阅读后获益良多,故撰此文和大家分享。 精彩脚本摘录 # 在每一行后面增加一空行 sed G   在参考手册中,命令G的作用是“将换行符后的保持空间内容追加到模式空间”。就像前文提到的,看过教程后只是熟悉了规则,还不能将规则运用自如,我自己写的代码是:sed 's/$/\n/',就是因为我还不熟悉每个命令会对模式空间产生什么影响。所以看到这段参考代码时感觉眼前一亮:“原来还可以这样写!” # 显示文件中的最后10行 (模拟“tail”) sed -e :a -e '$q;N;11,$D;ba'   假设文件有 N 行(N 大于10),显示最后10行也就意味着删除前的 N-10 行。在多行模式中,命令“D”可以删除模式空间中第一行;命令“N”可以将下一行追加到模式空间中,建立多行模式。因此问题转化为:“1)将整个文件的内容放入一个模式空间中;2)删除前 N-10 行。”其中问题1)通过控制语句“b”来解决:sed ':a; N; ba';至于问题二,模式“1,$”代表文本中的所有行,因此紧跟着的命令被执行N次,同理,模式“11,$”匹配后面的 N-10 行,因此“11,$D”一个执行了 N-10 次。   其实,在 GNU sed 中,命令“$q”是可以删掉的,因为在最后一行执行命令“N”就会因出错而自动退出。   另外,在

DAO层测试

<dependency> <groupId>com.wix</groupId> <artifactId>wix-embedded-mysql</artifactId> <version>2.1.4</version> <scope>test</scope> </dependency> 利用 wix-embedded-mysql 把MySQL嵌入到进程中,作为内存型的MySQL来做单元测试。 脚本: resources/migrations/mysql/<database>/<timestamp>_<action>.sql 但多个项目需要共享数据库脚本,可能可以用 git submodule 共享。