StackOverflowExceptionについて への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 トマト  (小学生)
投稿日時
2009/8/28 03:08:32
今、GetGCDを改良してみました。
結果は失敗です。
というよりも変な現象が起きました。
テスト用コード
これを実行すると、GetGCDの"If Not IsDecimal(inting) Then"の行で呼び出しているIsDecimalの "For Each c As Char In Nomber.ToString"の行で発生しました。
でも変です。
ToDoubleではReduceは呼び出さないはずです。
IsDecimalのローカル
もっと探ってみました。
すると、Denominatorという分母のプロパティのSetの中のReduce()の背景の色が変わっていました。
どこからも呼び出していないのに・・・。不思議です。
Public Function GetGCD(ByVal Int1 As Integer, ByVal Int2 As Integer) As Integer
'小さいほうを探す
Dim Mini As Integer = Math.Min(Int1, Int2)
Dim Int1_List As New List(Of Integer)
Dim OKList As New List(Of Integer)
Dim inting As Double
'Int1を確認
For i As Integer = 1 To Mini
inting = Int1 / i
If Not IsDecimal(inting) Then
Int1_List.Add(i)
End If
Next
'Int2を確認
For i As Integer = 1 To Mini
inting = Int2 / i
If Not IsDecimal(inting) AndAlso Int1_List.Contains(i) Then 'ここを改良しました。
OKList.Add(i)
End If
Next
Return OKList(OKList.Count - 1)
End Function
結果は失敗です。
というよりも変な現象が起きました。
テスト用コード
Sub Main()
Application.EnableVisualStyles()
Dim f As New Fraction(5, 87)
MsgBox(f.ToDouble)
End Sub
これを実行すると、GetGCDの"If Not IsDecimal(inting) Then"の行で呼び出しているIsDecimalの "For Each c As Char In Nomber.ToString"の行で発生しました。
でも変です。
ToDoubleではReduceは呼び出さないはずです。
IsDecimalのローカル
IsDecimal False
Nomber 1.25
もっと探ってみました。
すると、Denominatorという分母のプロパティのSetの中のReduce()の背景の色が変わっていました。
どこからも呼び出していないのに・・・。不思議です。
投稿者 トマト  (小学生)
投稿日時
2009/8/28 02:47:32
よくよくコードを見てみるとGetGCDに無駄がありそうです。
これから、修正してみます。
これから、修正してみます。
投稿者 るきお  (社会人)
投稿日時
2009/8/27 22:26:35
こんにちは。
現象が再現できるコードがないと回答しにくいです。
一般的には数学などのように同じ処理を何度も何度も繰り返す場合、
同じメソッドが何度も何度も入れ子上に呼び出されStackOverflowの例外が発生します。
次の例は、処理のないように意味はありませんがStackOverflowが発生するシンプルな例です。
この例外を回避する代表的な方法は、
1.ロジックを見直して再帰が発生しないようにする。→再帰ではなくループを使う。
3.求める精度を低くする。→再帰回数カウント、求める値の桁数のチェックなどをして処理の停止条件とする。
3.StackOverflowの例外をCatchする。
といったところです。
現在では3は推奨されていないようです。
現象が再現できるコードがないと回答しにくいです。
一般的には数学などのように同じ処理を何度も何度も繰り返す場合、
同じメソッドが何度も何度も入れ子上に呼び出されStackOverflowの例外が発生します。
次の例は、処理のないように意味はありませんがStackOverflowが発生するシンプルな例です。
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim i As Integer
i = AddOne(0)
End Sub
Private Function AddOne(ByVal value As Integer) As Integer
value += 1
Return AddOne(value)
End Function
この例外を回避する代表的な方法は、
1.ロジックを見直して再帰が発生しないようにする。→再帰ではなくループを使う。
3.求める精度を低くする。→再帰回数カウント、求める値の桁数のチェックなどをして処理の停止条件とする。
3.StackOverflowの例外をCatchする。
といったところです。
現在では3は推奨されていないようです。
投稿者 刈谷勇  (社会人)
投稿日時
2009/8/27 22:19:55
こんにちは、トマトさん。
>分数のクラスを作っているのですが計算中にStackOverflowExceptionが発生します。
StackOverflowExceptionが発生する場所はどこで出ているのでしょうか?
また、提示していただいたプログラムのどのメソッドを呼んで、そのときの各変数等の値がどのようになっているのかを提示していただけないでしょうか?
※GetGCDはもっと簡単に書けるような気が・・・
>分数のクラスを作っているのですが計算中にStackOverflowExceptionが発生します。
StackOverflowExceptionが発生する場所はどこで出ているのでしょうか?
また、提示していただいたプログラムのどのメソッドを呼んで、そのときの各変数等の値がどのようになっているのかを提示していただけないでしょうか?
※GetGCDはもっと簡単に書けるような気が・・・
投稿者 おおぎっち  (社会人)
投稿日時
2009/8/27 07:56:55
答えじゃありませんが気になったので
CCDもGCMもあってます。
ほかにはGCFとかいったりもします。
嗚呼、これだけですみません。
CCDもGCMもあってます。
ほかにはGCFとかいったりもします。
嗚呼、これだけですみません。
投稿者 トマト  (小学生)
投稿日時
2009/8/27 07:53:58
一応Yahoo!辞書で調べたのですが…。
投稿者 まだまだ  (中学生)
投稿日時
2009/8/27 06:25:17
こんにちは
すみません、答えではないのですが、最大公約数は
「GCD」ではなく「GCM」ではなかったでしょうか?
答えではなくてすみません。
すみません、答えではないのですが、最大公約数は
「GCD」ではなく「GCM」ではなかったでしょうか?
答えではなくてすみません。
投稿者 トマト  (小学生)
投稿日時
2009/8/27 01:45:07
こんにちは。質問ばかりですいません。
分数のクラスを作っているのですが計算中にStackOverflowExceptionが発生します。
MSDNによると「入れ子のメソッド呼び出しが多すぎて実行スタックがオーバーフローすると、 StackOverflowException 例外がスローされます。」とのことです。
これを回避する方法はありませんか?
コードを載せておきます。
ちょっと読みにくくなってしまいました。
分数のクラスを作っているのですが計算中にStackOverflowExceptionが発生します。
MSDNによると「入れ子のメソッド呼び出しが多すぎて実行スタックがオーバーフローすると、 StackOverflowException 例外がスローされます。」とのことです。
これを回避する方法はありませんか?
コードを載せておきます。
''' <summary>小学校で習うような簡単な数学を集めました。</summary>
Public Module EasyMath
'中略
''' <summary>最大公約数を取得します。</summary>
''' <param name="Int1">1つ目の数字を指定します。</param>
''' <param name="Int2">2つ目の数字を指定します。</param>
Public Function GetGCD(ByVal Int1 As Integer, ByVal Int2 As Integer) As Integer
'小さいほうを探す
Dim Mini As Integer = Math.Min(Int1, Int2)
Dim Int1_List As New List(Of Integer)
Dim OKList As New List(Of Integer)
Dim inting As Double
'Int1を確認
For i As Integer = 1 To Mini
inting = Int1 / i
If Not IsDecimal(inting) Then
Int1_List.Add(i)
End If
Next
'Int2を確認
For i As Integer = 1 To Mini
inting = Int2 / i
If Not IsDecimal(inting) Then
If Int1_List.Contains(i) Then
OKList.Add(i)
End If
End If
Next
Return OKList(OKList.Count - 1)
End Function
''' <summary>数字が小数か確認します。</summary>
''' <param name="Nomber">確認する数字を指定します。</param>
''' <returns>小数ならTrue でないならFalseを返します。</returns>
<Extension()> Public Function IsDecimal(ByVal Nomber As Decimal) As Boolean
Dim NomberStr As String = CStr(Nomber)
For Each c As Char In NomberStr
If c = "."c Then
Return True
End If
Next
Return False
End Function
''' <summary>分数を表します。</summary>
''' <remarks>約分は自動で行われます。</remarks>
<Serializable()> Public Class Fraction
Implements IConvertible
'中略
''' <summary>約分をします。</summary>
Protected Friend Sub Reduce() '計算のメソッドがこのメソッドを実行したときにどこかの行で発生します。
Dim gcd = GetGCD(Me.Denominator, Me.Numerator)
Me.Denominator \= gcd
Me.Numerator \= gcd
End Sub
'中略
End Class
End Module
ちょっと読みにくくなってしまいました。
ここでDenominatorにアクセスして無限にループしていたみたいです。