[SML 7344] Re: 合計ぜすに平均を
Shin Sahara from Home
shinsahara @ shinsahara.com
2007年 12月 13日 (木) 15:27:39 JST
佐原です。
On 2007/12/12, at 15:01, AOKI Atsushi wrote:
> 青木@SRA先端技術研究所です。
>
> 一見、簡単そうな「平均(相加平均)を求める」プログラムを考え
> てみましょう。実は大変に奥深い内容を含みます。皆さんのプログ
> ラミングに対する話題のネタにしていただければ幸いです。
>
> たとえば、999人の成績(百点満点)の平均を求めるプログラム
> なんて、誰にでも作れそうですが、はたして本当でしょうか?
>
> まず、999人の成績の仮データを生成するところが難しいでしょ。
> 乱数を使えば、なんとかなりそうですが、一様分布しか得られない
> ことが多いはず。実際には正規分布しますもん。正規分布した仮の
> 成績データを即座に作り出せるプログラマが少ないですよね。
>
> それに、平均を求めるのに、999人の成績を合計して、人数で割
> る、なんてことをしたら、それこそペケ(平均プログラマ以下)。
でも、1 / numberOfPeople って、結局、全体を人数で割る
ことに変わりないような気がするのですが...
私が作ったVDM++のライブラリでは、以下のようにペケしていま
す :-)
もちろん、こうした方が「証明が簡単なんだもん」という言い訳が
あります。
--列sの要素の平均を求める
static public 平均を得る[@型]: seq of @型 -> [real]
平均を得る(列) == if 列 = [] then nil else
平均を得る補助関数[@型](0)(0)(列);
static 平均を得る補助関数[@型] : @型 -> @型 ->
seq of @型 -> real
平均を得る補助関数(合計)(要素数)(列) ==
cases 列 :
[先頭] ^ 後続列 -> 平均を得る補助関数[@
型](合計 + 先頭)(要素数 + 1)(後続列),
[] -> 合計 / 要素数
end;
以上。
Σ忘年会+宴会 = 99.2kg
> 合計を使わないこと、999人も仮であり、人数はこれからもどん
> どん増えて、合計は桁あふれする恐れがあること、それでも即時に
> 平均を応答できなければならないこと、これらを満たすプログラム
> (平均というオブジェクト)の作成です。
>
> 末尾に完全なプログラム(Smalltalk らしいメタなプログ
> ラム)を
> 添付しておきますが、要と記すと以下のようになります。
>
> | normalDistribution numberOfPeople averageValue resultValue |
> normalDistribution := JunNormalDistribution mean: 50 deviation: 15.
> numberOfPeople := 0.
> averageValue := 0.
> 999 timesRepeat:
> [resultValue := 0 max: (normalDistribution next min: 100).
> numberOfPeople := numberOfPeople + 1.
> averageValue := averageValue + ((resultValue - averageValue)
> * (1 / numberOfPeople))].
> ^averageValue
>
> 平均50点で偏差15の正規分布した仮の成績データをこしらえな
> がら、合計をすることなく、平均を計算しています。多倍長整数演
> 算、分数、そして、浮動小数点ではない固定小数点数、などが具備
> されたオブジェクト指向プログラミング言語ならではですね。
>
> 新たな成績(resultValue)を加えたときの新たな平均と
> は、その成
> 績の昔の平均からのズレ(resultValue - averageValue)
> に対して
> 影響力(1 / numberOfPeople)を乗じたものを、昔の平均
> に加えた
> ものである、というところにあります。
>
> 多くの人の中で一人だけ突出しても、その影響は大したことないの
> が明解です。また、総数を2とした特殊な場合、足して2で割れば
> いいことも導出されます。
>
> 30、50、70、90、・・・、と来たとき、私たちはいちいち
> 合計して総数で割って平均なんか求めていないのよねぇ〜。突出を
> 演出したい(自分の影響力を出したい)のに、衆(多勢)を頼むな
> んて可笑し過ぎますぅ〜。
>
> ------------------------------------------------------------
> R2D2 (AOKI Atsushi) http://www.sra.co.jp/people/aoki/
>
>
> | aClass normalDistribution averageObject |
> aClass := Smalltalk.Jun
> defineClass: #JunAverageObject
> superclass: #{Jun.JunAbstractObject}
> indexedType: #none
> private: false
> instanceVariableNames: 'numberOfPeople averageValue '
> classInstanceVariableNames: ''
> imports: ''
> category: 'Jun-Goodies-Misc'.
> aClass
> compile: 'initialize
> super initialize.
> numberOfPeople := 0.
> averageValue := 0'
> classified: 'initialize-release' asSymbol;
> compile: 'value
> ^averageValue'
> classified: 'accessing' asSymbol;
> compile: 'add: resultValue
> numberOfPeople := numberOfPeople + 1.
> averageValue := averageValue + ((resultValue - averageValue) *
> (1 / numberOfPeople))'
> classified: 'adding' asSymbol.
> (Kernel.Parcel parcelNamed: 'Jun') addClass: aClass.
> (Store.Registry packageNamed: 'Jun-Goodies-Misc')
> addEntiretyOfClass: aClass.
>
> [normalDistribution := JunNormalDistribution mean: 50 deviation: 15.
> averageObject := aClass new.
> 999 timesRepeat: [averageObject add: (0 max: (normalDistribution
> next min: 100))].
> ^averageObject value]
> ensure: [aClass removeFromSystem]
>
>
> ------------------------------------------------------------
>
-----------------------------------------------------------------------
Imagine the World Movement!
Shin Sahara
E-Mail: ss @ shinsahara.com http://shinsahara.com
Phone: +81-80-5402-9755(in Japan and Corea), +81-80-5030-9755(in the
world except Corea)
+81-80-1114-3378(in Corea, Hong Kong, Taiwan, Europe)
------------------------------------------------------------------------
SML メーリングリストの案内