相乗平均、調和平均を求めたいのですが・・・


ヒロフサ  2004-08-04 17:14:06  No: 10228

相乗平均、相加平均を求めたいのですが、文系なもんで理解は出来るが組み立てが出来ません。
なんか便利に使えるような関数も有りそうだし、式自体は単純なのですが、意外に思い計算になってしまうような気もしますし・・・・
どなたか  助けていただければ幸いです。


ヒロフサ  2004-08-04 19:46:03  No: 10229

本文間違えました
「相加平均」ではなくって「調和平均」でした
相加平均は簡単にだせますよね  
申し訳ありません
よろしくお願いします


にしの  2004-08-04 19:58:38  No: 10230

誤差を考えると、多倍長演算にしないといけないかもしれませんが。
こんな感じでしょうか。
式をそのまま当てはめただけなので、速度的にも精度的にも問題があると思います。

//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;


にしの  2004-08-04 20:59:29  No: 10231

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;


おやじ  2004-08-04 22:55:09  No: 10232

//相乗平均
対数で和をとり、最後に逆対数変換すれば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;


ヒロフサ  2004-08-05 01:22:01  No: 10233

ありがとうございました
早速、あててみます。

なんかすごく嬉しいです。


とおりすがりん  2004-08-05 04:37:06  No: 10234

Aのn乗根は
power(A,1/n)
ではないですか・・?


にしの  2004-08-05 05:24:41  No: 10235

それは知りませんでした^^;
Cの頃は、第2引数は整数でしたから。
こっちのほうが早いですね。
負値では例外になってしまうみたいですが。


とおりすがりん  2004-08-05 06:05:36  No: 10236

c++builderだとmath.hでは
double pow(double x, double y)
となっているようですが。

その定義上、
x が 0 よりも小さい実数でy が非整数の場合
x が 0 で y が 0 より小さい場合
x=y=0の場合
は処理できませんが。


にしの  2004-08-05 08:24:48  No: 10237

Borland C++ Compiler 5.5でも同じく(double,double)でした。
LSI-C86試食版でもdoubleでした。

おそらく、遠い昔Z80系のCでそう覚えたのだと思います^^;
混乱させてすみません。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加