■bashとclispとawkで小学三年生レベルの等差数列の総和
フィボナッチ数列で知られるレオナルドの算盤の書にある。
ガウスは小学校三年生で再発見したとされている。
よって、タイトルは釣りです。
等差数列
http://ja.wikipedia.org/wiki/%E7%AD%89%E5%B7%AE%E6%95%B0%E5%88%97
■初項1、項差1、項数100のbash+awk文。
$ echo "`seq 1 1 100`" | \
awk '{sum+=$1;printf "%d+",$1};END{print "\n"sum}' | \
sed s/"+\$"/"="/ | nkf -f70
1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+
28+29+30+31+32+33+34+35+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50+51+
52+53+54+55+56+57+58+59+60+61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+
76+77+78+79+80+81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+
100= 5050
■上記をclispに渡すように書くと以下になる。
$ echo "(+ `seq 1 100`)" | clisp -q
[1]>
5050
■ガウスの解法の考え方が見えるように書くと。。。
※50と100以外は2組で100。
$ for n in "`seq 1 49`";do \
echo "$n" | awk '{print $1"+"100-$1"="$1+(100-$1)}'; \
done | \
awk -F\= '{sum+=$2;print $0}END{print sum+50+100}' | \
column | \
sed s/"\t\([0-9]*\$\)"/"\n\n\1"/
1+99=100 11+89=100 21+79=100 31+69=100 41+59=100
2+98=100 12+88=100 22+78=100 32+68=100 42+58=100
3+97=100 13+87=100 23+77=100 33+67=100 43+57=100
4+96=100 14+86=100 24+76=100 34+66=100 44+56=100
5+95=100 15+85=100 25+75=100 35+65=100 45+55=100
6+94=100 16+84=100 26+74=100 36+64=100 46+54=100
7+93=100 17+83=100 27+73=100 37+63=100 47+53=100
8+92=100 18+82=100 28+72=100 38+62=100 48+52=100
9+91=100 19+81=100 29+71=100 39+61=100 49+51=100
10+90=100 20+80=100 30+70=100 40+60=100
5050
■上記をclispに渡すように書くと。
$ for n in `seq 1 49`;do echo "$n $((100-$n))" ;done | \
xargs echo -n | \
sed s/"^"/"(+ "/ | \
sed s/"\$"/" 50 100)"/ | \
clisp -q
[1]>
5050
■上記の考えのまま、公式にすると、以下のようになる。
(n/2-1)*n+n+(n/2)
$ echo "100" | awk '{print ((($1/2)-1)*$1)+$1+($1/2)}'
5050
■clispに渡すように書くと以下のように素敵なことになる。
括弧を見ただけで、計算順序のレイヤーを頭の中に描ける人はかなりの変態です。
$ echo "(+ (+ (* (- (/ 100 2) 1) 100 ) 100) (/ 100 2))" | clisp -q
[1]>
5050
■また、以下のようにもまとめられます。
(n/2)*n+(n/2)
$ echo "100" | awk '{print (($1/2)*$1)+($1/2)}'
5050
■clispでは共通項が見やすい。
$ echo "(+ (* (/ 100 2) 100) (/ 100 2))" | clisp -q
[1]>
5050
■もう少しまとめると暗算が簡単になる。
(n+1)(n/2)
$ echo "100" | awk '{print (($1+1)*$1)/2}'
5050
■clispでも格段に読みやすくなりました。
$ echo "(/ (* (+ 100 1) 100) 2)" | clisp -q
[1]>
5050
■項数=n項なので公式に入れるのはそれほど難しくありません。
コメント行はシェルが無視してくれます。
$ echo "a1 d n" |
sed s/"a1"/"1"/ | \
sed s/"d"/"1"/ | \
sed s/"n"/"100"/g | \
awk '{print (($3*((2*$1)+(($3-1)*$2))))/2}'
5050
■clispの場合も同じです。
$ echo "(/ (* n (+ (* 2 a1) (* (- n 1) d))) 2)" | \
sed s/"a1"/"1"/ | \
sed s/"d"/"1"/ | \
sed s/"n"/"100"/g | \
clisp -q
[1]>
5050
■変更したいsed行を修正します。
以下はn項までの数を1000にしています。
$ echo "a1 d n" | \
sed s/"a1"/"1"/ | \
sed s/"d"/"1"/ | \
sed s/"n"/"1000"/g | \
awk '{print (($3*((2*$1)+(($3-1)*$2))))/2}'
500500
$ echo "`seq 1 1000`" | awk '{sum+=$1}END{print sum}'
500500
$ echo "(/ (* n (+ (* 2 a1) (* (- n 1) d))) 2)" | \
sed s/"a1"/"1"/ | \
sed s/"d"/"1"/ | \
sed s/"n"/"1000"/g | \
clisp -q
[1]>
500500
■以下は項数で求める公式です。
項差が変わる場合、項数=n項では無くなり、
seqに渡すには、項数に応じたn項の数が必要になります。
$ echo "a1 d n" | \
sed s/"a1"/"1"/ | \
sed s/"d"/"2"/ | \
sed s/"n"/"1000"/g | \
awk '{print (($3*((2*$1)+(($3-1)*$2))))/2}'
1000000
$ echo "(/ (* n (+ (* 2 a1) (* (- n 1) d))) 2)" | \
sed s/"a1"/"1"/ | \
sed s/"d"/"2"/ | \
sed s/"n"/"1000"/g | \
clisp -q
[1]>
1000000
■n項までの数を元に、初項+項差*(n項までの数-1)でn項が求まります。
$ echo "1 2 1000" | awk '{print $1,$2,$1+($2*($3-1))}' | seq `xargs` | wc -l
1000
$ echo "1 2 1000" | awk '{print $1,$2,$1+($2*($3-1))}' | seq `xargs` | tail -1
1999
$ echo "1 2 1000" | awk '{print $1,$2,$1+($2*($3-1))}' | seq `xargs` | awk '{sum+=$1}END{print sum}'
1000000
■clispの方が直感的だったりします。
$ echo "(+ 1 (* 2 (- 1000 1)))" | clisp -q
[1]>
1999
■bashとawkとclispは仲良しです。
$ echo "初項=1、項差=2、項数=1000"; \
echo "(+ 1 (* 2 (- 1000 1)))" | \
clisp -q | \
tail -1 | \
seq 1 2 `xargs` | \
sed s/" "/"\n"/g | \
awk '{sum+=$1}END{print "等差数列の総数:"sum}'
初項=1、項差=2、項数=1000
等差数列の総数:1000000
■1から100までの間の偶数の総和。
項数は半分になるのは分かりますよね。。。
$ echo "初項=2、項差=2、項数=50"; \
echo "(+ 2 (* 2 (- 50 1)))" | \
clisp -q | \
tail -1 | \
seq 2 2 `xargs` | \
sed s/" "/"\n"/g | \
awk '{sum+=$1}END{print "等差数列の総数:"sum}'
初項=2、項差=2、項数=50
等差数列の総数:2550
■n番目の項が分かっているので、以下でもかまいません。
$ echo "`seq 2 2 100`" | awk '{sum+=$1}END{print sum}'
2550
■公式をそのまま使うと以下の通りです。
$ echo "a1 d n" | \
sed s/"a1"/"2"/ | \
sed s/"d"/"2"/ | \
sed s/"n"/"50"/g | \
awk '{print (($3*((2*$1)+(($3-1)*$2))))/2}'
2550
$ echo "(/ (* n (+ (* 2 a1) (* (- n 1) d))) 2)" | \
sed s/"a1"/"2"/ | \
sed s/"d"/"2"/ | \
sed s/"n"/"50"/g | \
clisp -q
[1]>
2550