[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 メーリングリストの案内