イルゥの屋根裏


Home Profile PC AV PHOTO 他趣味 更新履歴

適当にルートを求めてみる

ルート、平方根

今回ここで扱うのは、平方根、ルートになります。y=(x)2

  1. GUI設計
  2. ルートを求めたい数値の取得
  3. ルートを整数演算
  4. 整数演算結果を引き継ぎ、小数点演算で精度を上げる
  5. 演算結果の提示

とても簡単です。ようは見た目を作って、数値を入力して、計算開始をして、結果を見るプログラムです。つまり、単機能プログラム。ちなみに私はこのプログラムを作った後に、Windowsに標準でついてくる電卓にルート計算の機能があったことを知りました。まさに、一見キニシナイ位置にあるから5年も気がつかなかったわけだ。

私の設計GUI

とまあ、なんか、適当に作った割には普通に使うだけならいい精度を持っています。えーとそれとぶっちゃけていうとあまり作りこんでいないのでwindowsの電卓の精度にも完膚なきまでに負けます。まああくまでもどのようにルートを求めたいかという代物です。

全体ソース・変数宣言 ちなみに全部Double型
in_v; 入力した数値です
out_u; 算出したルートより低い数値で、近い数値です。
out_c; 算出したルートを格納します。
out_o; 算出したルートより高い数値で、近い数値です。
out_mpu; out_uを二乗した数値です。
out_mpc; out_cを二乗した数値です。
out_mpo; out_oを二乗した数値です。
mp; 内部計算で、二乗した数値を格納します。
c5; 小数点の足し引きで使います。
x; 二乗ターゲットです。
y; 二乗ターゲットです。
bw10; えーと、確か1〜0の間の処理使う予定だった。未使用ヽ(;´Д`)ノ

ボタンクリック時の動作
get_in_v();
mth_over1();
mth_float();
output_u.Text = out_u.ToString();
output_o.Text = out_o.ToString();
output_c.Text = out_c.ToString();
output_mpu.Text = out_mpu.ToString();
output_mpo.Text = out_mpo.ToString();
output_mpc.Text = out_mpc.ToString();

作ったときは適当にやって、あとで整理すればいいやと思っていたらこの日を迎えてしまいました。まずはプログラムが起動時に、必要な変数を宣言します。数値を画面に入力して、ルート計算をクリックすれば計算されると言うわけです。ボタンクリックのソースが短いですが、流れを分離して考えるために別記で呼び出し式にしてあります。

get_in_v();のソース

if (double.TryParse(input_v.Text, out in_v) == true)
{}
else
{in_v = 0;}

まずは数値取得から。まず、GUIに入力後、GUIの数値を文字列から数値に変換。TryParseなのは、変換できない場合も想定していると言うことです。これがないと入力していないときにクリックするだけで暴走します。このプログラムでは変数”in_v”に指定の値を格納します。

mth_over1();のソース
y = 0;
x = 0;
mp = y * x;
while (in_v > mp)
{
y = y + 1;
x = x + 1;
mp = y * x;
}
out_c = x;
out_mpc = out_c * out_c;
out_o = x;
out_o++;
out_mpo = out_o * out_o;
out_u = x;
out_u--;
out_mpu = out_u * out_u;

このプログラムは、ループ処理を使いルートに近い値を算出します。xとyは作っているときの都合上で統合できませんでしたが、両方同じ値をとり、xとyを掛け合わせることにより、二乗を行います。ルートを求めたい数値を、二乗した数字が超えるまで二乗される数値の値を1ずつ数値を増やして、一致、もしくは超えるまで計算します。このループを抜けると、次の工程で精度を高めます。

mth_float();のソース
{
c5 = 1;
for (int fc = 0; fc < 32; ++fc) ループ開始
{
if (mp == in_v) 二乗して同じであれば、その数値がルート。
{break;}     上記の理由のために、ループを抜ける。
else
if (mp > in_v) 二乗すると大きくなるので、小さくする処理。
{
y = y - c5;
x = x - c5;
mp = x * y;
}
else
if (mp < in_v) 二乗しても数値が足りないので、足りるようにする処理。
{
y = y + c5;
x = x + c5;
mp = x * y;
}
else
{break;}
c5 = c5 / 2; ループの最後にc5を半分にする。
}       ループの末端
out_c = x;
out_mpc = out_c * out_c;

このプログラムでは、先ほど求めたルートに近い値の小数点を計算して、二乗した際の誤差を縮めます。最初は比較をします。一致している場合は何もせずループを抜け、表示する処理に移ります。二乗した時にオーバー(in_v<mp)する場合、xとyからc5を引きます。二乗した時に超えない場合(in_v>mp)の場合、xとyにc5を足します。足し引きするたびにc5は半分になるので、0.5>0.25>0.125と減っていきます。ちなみに32回ループしますが、これ以上ループしても精度はあまり変わらず、足りないと高い数字の精度が低くなるので、妥協点になります。

output_mpu.Text = out_mpu.ToString();
output_mpo.Text = out_mpo.ToString();
output_mpc.Text = out_mpc.ToString();

最終工程です。計算した数値を画面に表示します。最後についているo.c.uについての説明。oはオーバー、整数段階で算出した値+1の数値、画面の右縦列。uはアンダー。整数段階で算出した値-1の数値、画面の左縦列。cは最終的に算出された数値、画面の中央列。オーバーとアンダーの意味は、実は個人的なデバッグ目的で、途中までしっかり動いているかを確認しているだけで、とくに意味はありません。

製作時の注意としては、入力できる文字数を制限しました。確か10桁で、あまり大きな桁の数字を入れると、フリーズするので桁数を制限しました。まあ流石にこんな膨大な桁を扱うのであればちゃっちいGUIなこれより別の計算アプリのほうがいいかもです。

総括

上記のような流れで、ルートはある程度求めれますが、意外と簡単な数値のルートを正確に算出できません。1.21のルートは1.1ですが、このプログラムでは0.5>0.25>0.125と小数点が進行する関係上、逆に近くなっても正確に算出できません。あくまでも、大体かつ適当なプログラムなのです。今後としては、1/2ではなく、1/10と多重ループを駆使した処理を考案中です。次回はルートを適当に求める第二弾になりそうです。

プログラムトップへ

トップへ

PCトップへ