いや、まだだから

やまだの仮想庭園 ~ いつか実体の伴う日まで

目次

Blog 利用状況

記事カテゴリ

書庫

日記カテゴリ

リンク

1から10までの和を、ループを使わずに計算してみる

とある人が調べものをしていたら、私の名前がでてきたそうです。……どんな調べものだ、とツッコミを入れたくなる自分が悲しいやまだです。

祭なんかやられた日にはでてこないわけにはいかないなぁ、とw

でも、すでに出遅れてますけど orz

 

1.プログラミング技術を駆使して表現してみる。

……もうこの辺は、他の人に任せますw

2.ネタに走ってみる。

「55」

「1+2+3+4+5+6+7+8+9+10」

……って、もう二番煎じどころか三番煎じ以上……。

3.数式で表現してみる

「((n + 1) × n) ÷ 2」

で和をループを使わずに表現できますね。しかし、これだけでは Jitta さんの二番煎じ。

 

ここで、Jitta さんのところ では、桁あふれの話がされています。

より高次の桁数を表現するためには、偶数だったら「(n + 1) × (n ÷ 2)」、奇数だったら「((n + 1) ÷ 2) × n」とする、と。詳しくはJitta さんのところ で。

 

で、ここでも一つ踏み込んでみます。

4.ループも条件分岐も使わずに表現してみる。

もう、どうせなら、偶数や奇数の判断もなしに表現できないかと。

で、考えてみたのが、次の数式(ただし、整数演算)。

「((((n + 1) ÷ 2) × (n ÷ 2)) × 2) + ((n + 1) ÷ 2))」

検証してみます。ミソは、必ず n もしくは n+1 のどちらかが奇数どちらかが偶数になるということ。

 

n が奇数の場合は、(n + 1) が偶数になる。一方、n は 2 では割り切れないため、小数演算では 0.5 の端数が出る。

すなわち、整数演算では式の前半部分で ((n + 1) ÷ 2) × 0.5 × 2 が切り捨てられることになる。

だから、((n + 1) ÷ 2)) を加算してやれば整数演算での合計値は合うはず。

 

n が偶数の場合は、(n+1) が奇数になる。(n + 1)  は 2 では割り切れないため、小数演算では 0.5 の端数が出る。

すなわち、整数演算では式の前半部分で 0.5 × (n ÷ 2) × 2 が切り捨てられることになる。

だから、(n ÷ 2) を加算してやれば整数演算での合計値は合うはず。

上記の式では、(n ÷ 2) でなく ((n + 1) ÷ 2) となっているが、n が偶数の場合、整数演算では端数切り捨てのためどちらも同じ値になる。

 

ということでいかがでしょーか?なんか、間違ってます?

あ、演算の最適化はなし、という方向でw

投稿日時 : 2009年10月6日 0:23

Feedback

# re: 1から10までの和を、ループを使わずに計算してみる 2009/10/06 11:41 biac

> 「((((n + 1) ÷ 2) × (n ÷ 2)) × 2) + ((n + 1) ÷ 2))」

そんなむつかしー式を! f(^^;

連続した自然数の和は、
(アタマ + シッポ) * 個数 / 2
でイケますよ~

例1) 1~10
(1 + 10) * 10 /2
= 11 * 10 / 2
= 110 / 2
= 55

例2) 2~10 (例1より1少ない)
(2 + 10) * 9 /2
= 12 * 9 / 2
= 108 / 2
= 54

例3) 1~9 (例1より10少ない)
(1 + 9) * 9 /2
= 10 * 9 / 2
= 90 / 2
= 45

# re: 1から10までの和を、ループを使わずに計算してみる 2009/10/06 20:26 biac

ぅわ、ごめん m(_`_)m

> Jitta さんのところ では、桁あふれの話がされています
…のあたり、 読んでませんでした orz

# re: 1から10までの和を、ループを使わずに計算してみる 2009/10/06 23:28 biac

オオボケ噛ました罪滅ぼしw に、C# で検証してみました。 1から順番に10まで。 OK です。

// NUnit 2.5 + C# 2008 Exp.
[Test(Description = "1から連続した自然数の和")]
[TestCase(1, Result = 1, TestName = "1~ 1")]
[TestCase(2, Result = 3, TestName = "1~ 2")]
[TestCase(3, Result = 6, TestName = "1~ 3")]
[TestCase(4, Result = 10, TestName = "1~ 4")]
[TestCase(5, Result = 15, TestName = "1~ 5")]
[TestCase(6, Result = 21, TestName = "1~ 6")]
[TestCase(7, Result = 28, TestName = "1~ 7")]
[TestCase(8, Result = 36, TestName = "1~ 8")]
[TestCase(9, Result = 45, TestName = "1~ 9")]
[TestCase(10, Result = 55, TestName = "1~10")]
public int SumOfSeqNum(int n) {
return (((((n + 1) / 2) * (n / 2)) * 2) + ((n + 1) / 2));
}

ついでに、 一般化したほう、
(アタマ + シッポ) * 個数 / 2
C# で書くと
((m + n) * (n - m + 1) / 2); // m,n は自然数で、 m <= n
…のほうも、 同じように出来ないかと、 風呂の中で考えてみましたが。 ギブアップ。 f(^^;
剰余を使えば出来たんだけどね~
((n / 2 + (n % 2)) * (n + 1 - (n % 2)) - ((m - 1) / 2 + ((m - 1) % 2)) * (m - ((m - 1) % 2)));

# re: 1から10までの和を、ループを使わずに計算してみる 2009/10/07 1:25 やまだ

biacさん、コメント&フォローどうもです。
わかりにくい書き方で申し訳ないです。
それでさらにフォローまでいただいて重ね重ねお手数かけましたー。

> ついでに、 一般化したほう、
え?
f(n) = ((((n + 1) ÷ 2) × (n ÷ 2)) × 2) + ((n + 1) ÷ 2))
としたら、
f(n) - f(m-1)
では駄目なんでせうか?

# re: 1から10までの和を、ループを使わずに計算してみる 2009/10/08 0:10 biac

> f(n) - f(m-1)
> では駄目なんでせうか?

え!? あら、合ってるっぽい。 お見事! (@@;

m=1のときを検算してみる。
f(m-1) = (((((m-1) + 1) ÷ 2) × ((m-1) ÷ 2)) × 2) + (((m-1) + 1) ÷ 2))
= ((((0 + 1) ÷ 2) × (0 ÷ 2)) × 2) + ((0 + 1) ÷ 2))
= (((1 ÷ 2) × 0) × 2) + (1 ÷ 2))
= ((0 × 0) × 2) + 0)
= 0
したがって、m=1 のときは、
f(n) - f(m-1)

f(n)
と等価になる。(1~nの和になる)

まいりました~ m(_`_)m

数学的には、 f(0) は未定義なんだよね。 なので、 m=1 のときと m>1 のときで場合分けしないとイカン。 条件分岐が出てくるからダメ、と思考停止して放棄してました f(^^;

※ f(n) は、「1~nまでの連続した自然数の和」を求める関数なので、 f(0) は「1~0までの連続した自然数の和」ということになる。 そんな矛盾した引数を渡したら、 f() メソッドの入り口で ArgumentOutOfRangeException を喰らっちまうはずだよ~ (w

ついでに。
m~n の連続した自然数 (ただし m<=n) の和を求める関数 g(m,n) は、
g(m,n) = f(n) - f(m-1)
であることについて。

1~n までの連続した自然数の和を考える。
これは、2つの部分和、 1~(m-1) の和と m~nの和に分けることができる。
すなわち、
g(1, n) = g(1, m-1) + g(m, n)
である。 (ただし、m>1 のとき)
※ m=1 の場合、2つの部分和のうちの後者が 1~n となり、元と同じ。 つまり分割できていない。 あ、この観点から f() を拡張するなら、 f(0)=0 になるのが正しいのか。 f(^^;

さて、
g(1, n) = g(1, m-1) + g(m, n)
を適宜移項すれば、
g(m, n) = g(1, n) - g(1, m-1)
となり、
g(1, x) = f(x)
であったから、
g(m, n) = f(n) - f(m-1) (ただし、m>1 のとき)
である。

ところで、 f(0)=0 という拡張をするのはどうなんだろう?
それはつまり、 g(1,0)=0 ということなんだけど。
0 を含めるように、かつまた、m と n の大小関係を問わないように拡張するとして…
g(0,1)=1 とするのが自然だよねぇ。
そうすれば、
g(0,3) = g(0,1) + g(2,3)
= 1 + 5 = 6
= g(1,3)
となる。 また、 1~3 の和も、3~1の和も、加算に順序は関係無いから、どちらも 6。 すなわち、
g(1,3) = g(3,1) = 6
という交換則が成り立つ。
ところが、0 が入るときだけ、
g(0,1)=1, g(1,0)=0
であって、交換則が成り立っていない… (--;

というわけで、数学的には、
「g(m, n) = f(n) - f(m-1) (ただし、m>1 のとき)」
という後ろの但し書きは外したくないのですよ。
でも、プログラミング的には、 メソッド内部の計算アルゴリズムがどうなっていようと、外から見てちゃんと g(m, n) が計算できていれば (外部設計を満たしているなら)、それで OK なわけで。
表向き、「m~n の連続した自然数 (ただし m<=n) の和を求める関数 g(m,n) でござい」と言っておけば無問題。(^^;

# re: 1から10までの和を、ループを使わずに計算してみる 2009/10/09 19:14 やまだ

biac さん、コメントありがとうございます。
……いや、違うな。
エントリありがとうございますw
もう、ほんとに、こんなしっかりと書いていただいて感謝です。
取り急ぎ断片的にコメント。

> f(0) は未定義なんだよね。
ええ、確かにそういえなくもないですね。
> f(n) は、「1~nまでの連続した自然数の和」
えっと、ちょっとレトリックかまさせていただいて良いですかw
上記定義より、該当がないから f(n)=0 (n <=0) といえなくもないかと。
この場合、
> 1~3 の和も、3~1の和も、加算に順序は関係無い
「3~1」は ∑i (ただし、3<=i<=1) という意味で解釈すると、g(3,1)=0 で一貫性は保てるかと。

で、そうすると n<=0 の条件判定をどこか式の中に織り込まないといけない、という自己矛盾が発生してしまうんですよねぇ orz
これは「整数演算で絶対値を表現できたら解がでるはず!」とちょっと考えてみたのですが、どうしても 0 除算の可能性が出てきてしまい……瞑想中。
……この辺が限界なのかしら?

# re: 1から10までの和を、ループを使わずに計算してみる 2009/10/09 21:14 やまだ

うわ。
>瞑想中。
迷走中だw

まさしく迷走してるなーw

タイトル
名前
Url
コメント