2015年10月25日日曜日

ウラムの螺旋を描く[Processing]

 素数っていいですよね。孤高な感じがして。でもなんか覚えにくいイメージがありますね。私の場合は,数字を覚えるときに,数字が小さいとその数字を因数分解して覚えます。そうすると「ああ,2^2+3^3=108なのか。2,2,3,3で覚えやすいな」みたいなことがあるのですが,素数はそういった覚え方ができないのがまた逆に良いですね。

1.ウラムの螺旋とは


 ウラムの螺旋はウラムさんが見つけたものです。とりあえずこんな感じの図形のこと。なんとなくn斜めに線が浮かび上がっているのがわかるでしょうか。
 この図形は素数に当たる数字の場所を緑色に塗ったものです。素数というと,なんだか法則性があるようでないような感じがしますが,このように図にしてみると法則性がありそうだということがわかります。
 この図形の書き方は,数字をある規則によって並べていき,素数を塗ると幾つかの線が現れるというものです。以下にその数字の並べ方を書いておきます。自分の手で一回書いてみると面白いですよ。
素数を青色に塗ってみました。なんとなく線が浮かび上がってくるのがわかるでしょうか。なぜこのような性質があるのかに対して,証明は確かされていなかったはず。しかしこのウラムの螺旋から,素数を多く生産する数式がたくさん発見された。

 ちなみに二次式で素数を大量生産できる式といえばこんな式がある。
n=0なら41(素数),n=1なら43(素数),n=2なら47(素数),n=3なら53(素数)……と,n=39までは全部素数になる。この数式であらわされる素数をオイラー素数と言ったりする。昔この式であらわされる自然数は全部素数になるよ,というデマに騙されたことがある。n=41を入れれば合成数になることは明らかなのにね。

2.ソースコード


 余談はさておき,プログラムはこんな感じ。素数はエラトステネスの篩で計算した。色を塗る場所の計算がちょっと雑で,上の表とは違っているかもしれない。まぁでも見るだけなら問題ない。
 ホントよくこんなこと考えたよね。まず数字を並べたりしないし,素数を縫ったりもしないからなぁ……。

boolean[] Board;

void setup() {
  /* 適当な大きさでウィンドウを開く */
  size(512, 512);

  /* indexが素数ならfalseの配列を作る */
  Board = new boolean[width*height+1];
  Board[0] = Board[1] = true;

  /* 素数かどうかをあらかじめエラトステネスの篩で計算 */
  for (int i = 2; i < sqrt(Board.length) ; i++ ) {
    /* iが素数ならば */
    if ( Board[i] == false ) {
      /* その倍数は合成数 */
      for (int j = 2 * i; j < Board.length; j += i ) {
        Board[j] = true;
      }
    }
  }
}

void draw() {
  /* 背景を黒にする */
  background(0);

  /* 描画する色を緑にする */
  stroke(0, 255, 0);
  fill(0, 255, 0);
  
  /* 原点を中心に持ってくる */
  translate(width/2, height/2);

  /* 描画する座標 */
  int x = 0;
  int y = 0;
  /* 座標をどう動かすかを計算するための変数 */
  int dx = 1;
  int dy = 0;
  int n = 1;
  
  for (int i = 1; i < width * height + 1; i++ ) {
    /* 素数ならば描く */
    if ( Board[i] == false )
      rect(x, y, 1, 1);  

    /* iに応じて次の描画場所を決める */
    if ( n * n + 1 == i ) {
      dy = (n % 2)*2-1;
      dx = 0;
      n++;
    } else if ( n * n - n + 1 == i) {
      dx = (n % 2)*2-1;
      dy = 0;
    }
    x += dx;
    y += dy;
  }
}

0 件のコメント:

コメントを投稿