相乗平均、相加平均を求めたいのですが、文系なもんで理解は出来るが組み立てが出来ません。
なんか便利に使えるような関数も有りそうだし、式自体は単純なのですが、意外に思い計算になってしまうような気もしますし・・・・
どなたか 助けていただければ幸いです。
本文間違えました
「相加平均」ではなくって「調和平均」でした
相加平均は簡単にだせますよね
申し訳ありません
よろしくお願いします
誤差を考えると、多倍長演算にしないといけないかもしれませんが。
こんな感じでしょうか。
式をそのまま当てはめただけなので、速度的にも精度的にも問題があると思います。
//N乗根
function Nsqrt(Value: Extended; N: Integer): Extended;
var
s: Extended;
function Nsqrt_(Value: Extended; N: Integer): Extended;
var
s, last: Extended;
begin
last := 1.0;
if Value > 1 then
s := Value
else
s := 1;
while true do
begin
last := s;
s := (Value / Power(s, N - 1) + (N-1)*s) / N;
if not (s < last) then Break;
end;
Result := last;
end;
begin
Result := 0;
if Value = 0 then Exit;
s := Nsqrt_(Value, N);
Result := (Value / Power(s, N - 1) + (N-1)*s) / N;
end;
//相加平均
function ArithmeticMean(Value: array of Extended): Extended;
var
Ans: Extended;
i: integer;
begin
Ans := 0.0;
for i := 0 to High(Value) do
begin
Ans := Ans + Value[i];
end;
Result := Ans / (High(Value) + 1);
end;
//相乗平均
function GeometricalMean(Value: array of Extended): Extended;
var
Ans: Extended;
i: integer;
begin
Ans := 1.0;
for i := 0 to High(Value) do
begin
Ans := Ans * Value[i];
end;
Result := Nsqrt(Ans, High(Value) + 1);
end;
//調和平均
function HarmonyMean(Value: array of Extended): Extended;
var
Ans: Extended;
i: integer;
begin
Ans := 0.0;
for i := 0 to High(Value) do
begin
Ans := Ans + (1 / Value[i]);
end;
Result := 1 / (Ans / (High(Value) + 1));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Value: array[0..3] of Extended;
begin
Value[0] := 1.0;
Value[1] := 2.0;
Value[2] := 3.0;
Value[3] := 4.0;
Memo1.Lines.Add('相加平均:' + FloatToStr(ArithmeticMean(Value)));
Memo1.Lines.Add('相乗平均:' + FloatToStr(GeometricalMean(Value)));
Memo1.Lines.Add('調和平均:' + FloatToStr(HarmonyMean(Value)));
end;
1つ間違い^^;
このNsqrtでは、負値が使えません。
最初に絶対値にして、NsqrtのNが奇数なら負値にするようにすれば出来ます。
# 以下、Nsqrtの中身。
begin
Result := 0;
if Value = 0 then Exit;
s := Nsqrt_(Abs(Value), N);
Result := (Abs(Value) / Power(s, N - 1) + (N-1)*s) / N;
if ((N and 1) = 1) and (Sign(Value) = NegativeValue) then Result := -Result;
end;
//相乗平均
対数で和をとり、最後に逆対数変換すればN乗根が不要になります。
function GeometricalMean(Value: array of Extended): Extended;
var
Ans: Extended;
i: integer;
begin
Ans := 0;
for i := 0 to High(Value) do
Ans := Ans +Ln(Value[i]);
Ans:=Ans/((High(Value)+1);
Result := Exp(Ans);
end;
ありがとうございました
早速、あててみます。
なんかすごく嬉しいです。
Aのn乗根は
power(A,1/n)
ではないですか・・?
それは知りませんでした^^;
Cの頃は、第2引数は整数でしたから。
こっちのほうが早いですね。
負値では例外になってしまうみたいですが。
c++builderだとmath.hでは
double pow(double x, double y)
となっているようですが。
その定義上、
x が 0 よりも小さい実数でy が非整数の場合
x が 0 で y が 0 より小さい場合
x=y=0の場合
は処理できませんが。
Borland C++ Compiler 5.5でも同じく(double,double)でした。
LSI-C86試食版でもdoubleでした。
おそらく、遠い昔Z80系のCでそう覚えたのだと思います^^;
混乱させてすみません。
ツイート | ![]() |