Skip to content

Instantly share code, notes, and snippets.

@micromeeeter
Last active October 18, 2015 10:22
Show Gist options
  • Save micromeeeter/96ec6a710f41b8028c97 to your computer and use it in GitHub Desktop.
Save micromeeeter/96ec6a710f41b8028c97 to your computer and use it in GitHub Desktop.
Pascal'sTriangle
//This program is to be drawn by calculating the Pascal's triangle.
//
//パスカルの三角形を計算,描画するプログラムです.
//真面目に計算しているのである程度いくとintに収まりきらず正しくなくなります.
//パスカルの三角形で特定の自然数の倍数を塗りつぶしていくと規則的な図形が出てくるよ〜っていう性質を見たいときは
//訂正してくださった方のコメントを見てください...ありがとうございます
final int rowNum = 300; //Select an arbitrary natural number 任意の自然数を入れる
int[] termNum = new int[rowNum]; //Array that contains the number of terms in a row 一列における項数を入れる配列
int[] totalSum = new int[rowNum]; //Array that containts the total number of terms 項の総数を入れる配列
IntList theTerm = new IntList(); //ArrayList that containts the number of terms 項の数を入れる可変長配列
int a, w, h, num, multiple;
void beforeValueSetup(){
//termNum
for(int i = 0; i < termNum.length; i++){
termNum[i] = i + 1;
}
//totalSum
for(int i = 0; i < totalSum.length; i++){
if(i == 0){
totalSum[i] = 1;
}else{
totalSum[i] = totalSum[i - 1] + termNum[i];
}
}
}
void valueSetup(){
//theTerm
for(int i = 0; i < rowNum; i++){
for(int j = 0; j < termNum[i]; j++){
if(j == 0 || j == termNum[i] - 1){
num = 1;
}else{
num = theTerm.get(totalSum[i - 2] + (j - 1)) + theTerm.get(totalSum[i - 2] + j);
}
theTerm.append(num);
}
}
}
void setup(){
beforeValueSetup();
valueSetup();
size(1000, 850);
multiple = 2; //Multiple to fill 塗りつぶす倍数
textAlign(CENTER);
textSize(10);
a = 0;
w = width / termNum[rowNum - 1];
h = height / rowNum;
background(255);
fill(0);
}
void draw(){
translate(width / 2 + w / 2, 0);
for(int i = 0; i < rowNum; i++){
for(int j = 0; j < termNum[i]; j++){
if(i % 2 == 0){
if(theTerm.get(a) % multiple == 0){
ellipse((i / 2 - j) * w - w / 2, height / (rowNum * 2) + h * i, 2, 2);
}
//text(theTerm.get(a), (i / 2 - j) * w - w / 2, height / (rowNum * 2) + h * i);
}else{
if(theTerm.get(a) % multiple == 0){
ellipse((i / 2 - j) * w, height / (rowNum * 2) + h * i, 2, 2);
}
//text(theTerm.get(a), (i / 2 - j) * w, height / (rowNum * 2) + h * i);
}
a++;
}
}
noLoop();
}
@kimurakoichi
Copy link

draw() で取り出している theTerm.get(a) の値を println で出力させたのを眺めていると、
負の値がところどころ混じっているのに気がつきました。
そこで valueSetupを次のようにして調べてみました。

void valueSetup(){
  PrintWriter writer = createWriter("log.txt");
  for(int i = 0; i < rowNum; i++){
    for(int j = 0; j < termNum[i]; j++){
      if(j == 0 || j == termNum[i] - 1){
        num = 1;
      }else{
        num = theTerm.get(totalSum[i - 2] + (j - 1)) + theTerm.get(totalSum[i - 2] + j);
        if (num < 0) {
          writer.print(num);
          writer.print(" " + theTerm.get(totalSum[i - 2] + (j - 1)));
          writer.println(" " + theTerm.get(totalSum[i - 2] + j));
        }
      }
      theTerm.append(num);
    }
  }
  writer.flush();
  writer.close();
}

結果、20000個以上が負の値となっていました。
負の値になっているのはオーバーフローが起きているためであり、塗りつぶしの倍数を3以上にすると結果がおかしくなるのも
オーバーフローが原因だと思います。
試しに以下のようなRubyスクリプトでtermNum, totalSum, theTerm を計算して theTerm の最大値を求めてみたのですが、計算違いがなければ
46879851386413726396596877219532042439616327850040679460236176356487585010919795837930712
となりました。int ではとても収まらない数ですね。
theTermの値を求める計算式がどこからでているのかわかりませんが、オーバーフロー対策をしないといけないのではないでしょうか。

#void beforeValueSetup(){
#  //termNum
#  for(int i = 0; i < termNum.length; i++){
#    termNum[i] = i + 1;
#  }
#  
#  //totalSum
#  for(int i = 0; i < totalSum.length; i++){
#    if(i == 0){
#      totalSum[i] = 1;
#    }else{
#      totalSum[i] = totalSum[i - 1] + termNum[i];
#    }
#  }
# 
#}
def calcTermNum(n)
  [*1..n]
end
def calcTotalSum(n, termAry)
  ary = Array.new(n, 0)
  ary[0] = 1
  (1.upto(n-1)).each do |i|
    ary[i] = ary[i-1]+termAry[i]
  end
  ary
end

#void valueSetup(){
#  //theTerm
#  for(int i = 0; i < rowNum; i++){
#    for(int j = 0; j < termNum[i]; j++){
#      if(j == 0 || j == termNum[i] - 1){
#        num = 1;
#      }else{
#        num = theTerm.get(totalSum[i - 2] + (j - 1)) + theTerm.get(totalSum[i - 2] + j);
#      }
#      theTerm.append(num);
#    }
#  }
#}
def valueSetup(rowNum, termNum, totalSum)
  ary = []
  (0.upto(rowNum-1)).each do |i|
    (0.upto(termNum[i]-1)).each do |j|
      num = 0
      if j==0 || j==termNum[i]-1
        num = 1
      else
        v = totalSum[i-2]
        num = ary[v+j-1] + ary[v+j]
      end
      ary<<num
    end
  end
  ary
end

rowNum = 300

termNum  = calcTermNum(rowNum)
totalSum = calcTotalSum(rowNum, termNum)
theTerm  = valueSetup(rowNum, termNum, totalSum)

File.open("values.txt", "w") do |f|
  f.puts "termNum length=#{termNum.length}"
  termNum.each{|e| f.puts e}
  f.puts "totalSum length=#{totalSum.length}"
  totalSum.each{|e| f.puts e}
  f.puts "theTerm length=#{theTerm.length}"
  theTerm.each{|e| f.puts e}
  f.puts "max value of theTerm is #{theTerm.max}"
end

@kimurakoichi
Copy link

色々足し込んでいって作った数値を theTerm.get(a) % multiple == 0 で剰余を計算していますが、
剰余だけが必要であるのなら合計そのものをまじめに計算する必要はないので
数値が大きくなりすぎないようにいちいち剰余をとりながら theTerm に append するようにしてみました。
それっぽい結果になったようですがこれでいかがでしょうか?

final int rowNum = 300; //Select an arbitrary natural number 任意の自然数を入れる
int[] termNum = new int[rowNum]; //Array that contains the number of terms in a row 一列における項数を入れる配列
int[] totalSum = new int[rowNum];  //Array that containts the total number of terms 項の総数を入れる配列
IntList theTerm = new IntList();  //ArrayList that containts the number of terms 項の数を入れる可変長配列

int a, w, h, num, multiple; 

void beforeValueSetup(){
  //termNum
  for(int i = 0; i < termNum.length; i++){
    termNum[i] = i + 1;
  }

  //totalSum
  for(int i = 0; i < totalSum.length; i++){
    if(i == 0){
      totalSum[i] = 1;
    }else{
      totalSum[i] = totalSum[i - 1] + termNum[i];
    }
  }

}


void valueSetup(){
  for(int i = 0; i < rowNum; i++){
    for(int j = 0; j < termNum[i]; j++){
      if(j == 0 || j == termNum[i] - 1){
        num = 1;
      }else{
        num = theTerm.get(totalSum[i-2]+(j-1))+theTerm.get(totalSum[i-2]+j); 
        num %= multiple;  //***** 追加
      }
      theTerm.append(num);
    }
  }
}

void setup(){
  multiple = 7; //Multiple to fill 塗りつぶす倍数 ***位置を移動
  beforeValueSetup();
  valueSetup();
  size(1000, 850);

  textAlign(CENTER);
  textSize(10);

  a = 0;
  w = width / termNum[rowNum - 1];
  h = height / rowNum;

  background(255);
  fill(0);
}

void draw(){
    translate(width / 2 + w / 2, 0);
  for(int i = 0; i < rowNum; i++){
    for(int j = 0; j < termNum[i]; j++){
      if(i % 2 == 0){
        if(theTerm.get(a) % multiple == 0){
          ellipse((i / 2 - j) * w - w / 2, height / (rowNum * 2) + h * i, 2, 2);
        }
        //text(theTerm.get(a), (i / 2 - j) * w - w / 2, height / (rowNum * 2) + h * i);
      }else{
        if(theTerm.get(a) % multiple == 0){
          ellipse((i / 2 - j) * w, height / (rowNum * 2) + h * i, 2, 2);
        }
        //text(theTerm.get(a), (i / 2 - j) * w, height / (rowNum * 2) + h * i);
      }
      //println(theTerm.get(a));
      a++;
    }
  }
  noLoop();
}

@micromeeeter
Copy link
Author

お礼が遅くなりました、ありがとうございました!オーバーフロー現象に初めて出会って何がどうだかさっぱりだったので本当にありがたいです…!

大きな数を扱う時は何らかの工夫で上限を超えないようにするのが大切なのですね。勉強になりました…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment