質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

3回答

8339閲覧

ピタゴラスの定理を配列を使って証明したいです

57svu

総合スコア28

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2017/05/10 05:15

某サイトの問題で変数a,b,cがすべて1から100までの整数だとして
aa + bb = c*c を証明する問題ですが

配列を使って
左辺を二次元配列でまとめ
右辺を一次配列で構成し

if文で左辺と右辺が同じ数値になったときに
consoleで出力するということをしたいのですが

最後のif文の条件式で

型 'System.IndexOutOfRangeException' の
ハンドルされていない例外が prob8_1.exe で発生しました

とエラーが出てしまいます
なにが原因なのか自分ではわからないので教えていただきますでしょうか。

↓問題です。

prob8-1.(難易度★★)(ピタゴラス数)

a,b,cを、いずれも1以上100以下の整数とするとき、aa+bb=c*cを満たす、全てのa,b,cの組み合わせ全てと、その数を求め、画面に表示しなさい。ただし、a,bの数値の組み合わせが同じものも別のものとしてもかまわない。具体的には、a=3,b=4,c=5と、a=4,b=3,c=5は別の組み合わせとする。

引用元
( http://csharp.sevendays-study.com/problem7.html )

↓ 自分がかいたコードです

c#

1 2 3 int a,b,c; 4 5 int[] uhen = new int[101]; // 右辺の関数の配列を設定 6 7 for (c = 0; c < uhen.Length; c++) // cは1から100までの整数 8 { 9 uhen[c] = (c * c); 10 11 } 12 13 14 int[,] sahen = new int[101, 101]; // 左辺の関数の配列を設定 15 16 for ( a = 0 ; a < sahen.GetLength(0) ; a++ ){ // aは1から100までの整数 17 18 for ( b = 0; b < sahen.GetLength(1); b++ ){ // bは1から100までの整数 19 20 sahen[ a,b ] =( ( a*a )+( b*b ) ); // sahen は aの二乗とbの二乗をたしたもの 21 22 } 23 } 24 25 for (a = 0; a < sahen.GetLength(0); a++) 26 { 27 for (b = 0; b < sahen.GetLength(1); b++) 28 { 29 sahen[a, b] = ((a * a) + (b * b)); 30 31 if (sahen[a, b] == uhen [c] ) 32 { 33 Console.Write( "{0} * {0} + {1} * {1} = {2} * {2} ",a,b,c ); 34 Console.WriteLine(); 35 Console.Write( sahen [a,b] + " = " + uhen[c] ); 36 Console.WriteLine(); 37 Console.WriteLine(); 38 39 } 40 41 } 42 } 43 44

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

can110

2017/05/10 05:22

「if (sahen[a, b] == uhen [c] )」の「c」にはどんな値が入ると期待していますか?また実際にはどんな値になっていますか?
57svu

2017/05/10 05:27

sahenには1,4,9,16,25の25で uhenには0,1,4,9,16,25の25でコンソールされるのを期待していますが、ローカルでみるとa,b=0,c=101になっています
can110

2017/05/10 05:37

すでに回答ありますが、そういうことです。cの値を適切にセットするようにしましょう。
57svu

2017/05/10 06:06

適切にセットとはif 文にはいる前にc = とし定義しなおすということでしょうか?
can110

2017/05/10 06:20

いえ。a,bの2重ループ中で、cの値は(も)どうすべきなのか、よく考えてみてください。
guest

回答3

0

ベストアンサー

そりゃー…

cの値更新してないしっていうケアレスミスだね。

追記:for 文で c が Lengthと同じ値になったところで止まってるから、uhen[c]はOutOfRangeになるよね
例外はどこで発生したかちゃんと見ましょう。そうすれば自分で分かるはずです。

追記2:

不具合が起きている理由

ピタゴラスの定理の結果を出力するところのコードをよく見てみよう。

C#

1for (a = 0; a < sahen.GetLength(0); a++) 2{ 3 for (b = 0; b < sahen.GetLength(1); b++) 4 { 5 sahen[a, b] = ((a * a) + (b * b)); 6 7 if (sahen[a, b] == uhen[c]) 8 { 9 Console.Write("{0} * {0} + {1} * {1} = {2} * {2} ", a, b, c); 10 Console.WriteLine(); 11 Console.Write(sahen[a, b] + " = " + uhen[c]); 12 Console.WriteLine(); 13 Console.WriteLine(); 14 15 } 16 } 17}

cは変動しているだろうか。
cが記述されている箇所を抜き出してみよう。
if (sahen[a, b] == uhen[c])
Console.Write("{0} * {0} + {1} * {1} = {2} * {2} ", a, b, c);
Console.Write(sahen[a, b] + " = " + uhen[c]);

この中に、cを変動させているコードはあるかな?
ないよね。
つまり、cは変動していない。

この時のcが102だから、Index Out Of Range(配列の要素の範囲外にアクセスしている例外)が出ているけど、これを直せば=この証明が上手くいくわけじゃあないよね。

結果を探してくるコードをちゃんと挟まなきゃいけない。
c を 1 から 100 まで動かして、sahen[a, b]とuhen[c]が一致するかを調べるようにしなきゃダメさ。

投稿2017/05/10 05:20

編集2017/05/10 06:48
haru666

総合スコア1591

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

57svu

2017/05/10 06:05

値の更新というと今のままだと 101でとまってるため それをリセットするということでしょうか? はじめのfor文である101のレングスもエラーの原因ということでしょうか...
haru666

2017/05/10 06:09

えええっ。いや違うよ! ちょっとまってね、色々更新するよ
57svu

2017/05/10 06:10

すみません(T_T) 宜しくお願いします????⤵
haru666

2017/05/10 07:01

とりあえず、101はエラーの直接的原因じゃあないよ。 ただ、101が望ましいかっていうと微妙だけどね。 問題文は1から100って書いてあるんだろう、正しく動くようになった後で結果をチェックしたら何かおかしいことが分かると思うよ。
guest

0

配列を使っても自動的に組み合わせが解決されるわけではないから、何か組み合わせを見つける方法は作らなくてはいけないよ。
配列を使って先に計算結果を入れておけばそれがキャッシュになる。
でもそれは、多少速度が速くなるかもね、程度のもの。

解き方は色々ある。
一番シンプルなのは以下のような方法。
for 文と if 文で解いたってSubasicさんの回答もこういうのだと思う。

C#

1for (int a = 1; a <= 100; ++a) 2{ 3 for (int b = 1; b <= 100; ++b) 4 { 5 for (int c = a > b ? a : b; c <= 100; ++c) 6 { 7 if (a * a + b * b == c * c) 8 { 9 Result(a, b, c); 10 } 11 if (a * a + b * b <= c * c) 12 { 13 break; 14 } 15 } 16 } 17}

配列2つを組み合わせることはできる…のだが、何番目同士の要素を組み合わせているかわかる方法が添え字をつけない限りないため、for 文を3つ回す以外で「a, b, c」を得る方法がない。
このため、配列を使っても上記とあまり大差ないコードになりがち。

より複雑にして、要素自体を参照した際に a, b, c が取れるようにすることはできる。
でも随分複雑だし、いい方法とは言えない。

情報を持てる構造体を作り

C#

1public struct LeftHandSide 2{ 3 public LeftHandSide(int a, int b) 4 { 5 this.a = a; 6 this.b = b; 7 } 8 9 public int a { get; } 10 public int b { get; } 11 public int Value { get { return a * a + b * b; } } 12} 13 14public struct RightHandSide 15{ 16 public RightHandSide(int c) 17 { 18 this.c = c; 19 } 20 21 public int c { get; } 22 public int Value { get { return c * c; } } 23}

2つの配列の一致したものを取り出す。

C#

1// 配列に直接いれるよりそのコンテナを使う 2// 予めサイズは必要数分確保しておく 3var lefts = new List<LeftHandSide>(100 * 100); 4for (int a = 1; a <= 100; ++a) 5{ 6 for (int b = 1; b <= 100; ++b) 7 { 8 lefts.Add(new LeftHandSide(a, b)); 9 } 10} 11 12var rights = new RightHandSide[100]; 13for (int c = 1; c <= 100; ++c) 14{ 15 rights[c - 1] = new RightHandSide(c); 16} 17 18// Linqを使って、2つの配列の交差した結果を取り出す 19var results = lefts.Join( 20 rights, 21 left => left.Value, 22 right => right.Value, 23 (left, right) => new { left.a, left.b, right.c }); 24 25foreach (var result in results) 26{ 27 Result(result.a, result.b, result.c); 28}

早い方法とは言い難い。
メモリも沢山いるしね。


cだけを予め計算しておき、その組み合わせを探す場合はもっと簡単な方法がある。
Dictionaryを使う方法だ。
Dictionaryを使って、二乗したcの結果と、cの組み合わせを得られるようにする。
そうすれば、高速に一致するcがあるのかが分かる。
この場合、コンテナもcの結果だけで済む。

C#

1// 予め c の二乗と c の組み合わせを計算しておく。 2var candidates = new Dictionary<int, int>(); 3for (int c = 1; c <= 100; ++c) 4{ 5 candidates[c * c] = c; 6} 7 8for (int a = 1; a <= 100; ++a) 9{ 10 for (int b = a; b <= 100; ++b) 11 { 12 // cが見つかれば一致する整数があったということ 13 int c; 14 if (candidates.TryGetValue(a * a + b * b, out c)) 15 { 16 Result(a, b, c); 17 } 18 } 19}

1から100までの数値ならa*a + b*bの平方根を求める方法もある。
その結果が整数であるかどうかでピタゴラスの定理を満たす整数を知る。
あまりに大きい数値だと平方根の計算速度が不安だが、この数なら関係はない。

C#

1for (int a = 1; a <= 100; ++a) 2{ 3 for (int b = 1; b <= 100; ++b) 4 { 5 double sqrt = Math.Sqrt(a * a + b * b); 6 7 // 端数を切り落とし一致するかを調べることで、整数であることを知る 8 if (sqrt == Math.Floor(sqrt)) 9 { 10 int c = (int)sqrt; 11 if (c <= 100) 12 { 13 Result(a, b, c); 14 } 15 } 16 } 17}

なお、プログラム的な書き方で以下のように書くこともできる。

C#

1for (int a = 1; a <= 100; ++a) 2{ 3 for (int b = a; b <= 100; ++b) 4 { 5 // とりあえずcを整数値に変換する 6 int c = (int)Math.Sqrt(a * a + b * b); 7 8 // 結果が一致しなければ整数の平方根ではなかったということ 9 if (c <= 100 && a * a + b * b == c * c) 10 { 11 Result(a, b, c); 12 } 13 } 14}

結果を出力するResult関数は以下。

public static void Result(int a, int b, int c) { Console.WriteLine($"{a} * {a} + {b} * {b} = {c} * {c}"); Console.WriteLine($"{a * a} + {b * b} = {c * c}"); Console.WriteLine(); }

投稿2017/05/11 02:08

編集2017/05/11 02:13
haru666

総合スコア1591

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

丁寧なアドヴァイスありがとうございます。
一応、この形式は諦めてfor文の三重ループとif文で問題自体はクリアできました!
for文での全体構成がわかった上でこちらの形式で再度ご指摘も踏まえて見直したいと思います!
ありがとうございました!

投稿2017/05/11 01:11

57svu

総合スコア28

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問