息子が2月に,算盤の検定を受けるのだが,ここのところ調子が悪い。
自宅でやる練習では,結構な点数なのに,塾で受ける模擬テストになると,点が伸びない。
聞けば,練習問題は,ほとんど覚えてしまったのだという。
そこで,珠算1級検定用問題をエクセルで作成することにした。
ルールは,http://www.syuzan.net/shuan/kangaekata.htmlのとおり。
1級の場合は,
みとり算 10桁10題の足し算が6問,加減算が4問,うち1問は答えがマイナス(補数)
かけ算 実(5から7桁)×法(4から6桁)で,実+法が11桁 20問
わり算 実(規定なし)÷法(4から6桁)=商(4から6桁)で,法+商が10桁 20問
となっている。結構ややこしい。とてもいちいち考えて作ってはいられない・・・
で,乱数を使ってエクセルに問題を作らせることにした。
みとり算は,10桁の整数を適当に発生させる。負の数字の場所は前もって決めておく。補数の発生はコントロールできないので,補数が1個の場合のみ印刷するようフラグで判断させる。
わり算の「法+商が10桁」は,答え(商)と法を先に決めておき,逆算で実を決定する。端数処理は,逆算した実に適当な数を足す。(どうせ割り切れないのだから)
かけ算は,特に工夫の必要なし!
さて,この話の肝は,指定桁の数値を作ることだ。
で,ユーザー定義関数を作ることした。
イメージとしては,「=ユーザー定義関数名(整数部の桁数,小数部の桁数)」とやれば,「1,234.56789」と出てくる感じである。
指定桁の数字を作成するユーザー定義関数
Function SubgetRand(j As Integer, k As Integer) 'j 整数部桁数 k 小数部桁数 固定桁実数を求める
Application.Volatile' 自動計算ON
getranda:' 整数部の処理
If j = 0 Then a = 0: GoTo getrandb:' 整数部が0桁なら小数処理へ飛ぶ
a = Int(Rnd() * 10 ^ j)' 0.123456...*10^3=123.456... intで123
If Len(a) < j Then GoTo getranda:' rnd()=0.0001...*1000=0 の場合はやり直し
getrandb:' 小数部の処理
If k = 0 Then b = 0: GoTo eee:' 整数部が0桁なら小数処理へ飛ぶ
b =val (Left(Rnd(), k + 2))' 0.1200053456789 右から0.+k桁 0.000123456 3+2桁だと0.000 これを数値化しbに代入
If Len(b) < (k + 2) Then GoTo getrandb:' 桁が足りなければ,もう一度
eee:
p = Val(a) + Val(b)
If (j = 0) * (p > 1) Then GoTo getrandb:
SubgetRand = p
End Function
このコードの肝は,(Left(Rnd(), k + 2)と Len(b)の振る舞い。
いずれも文字列操作の関数で,「0.」を2文字と扱う。ここまでは,ちょっとWebを調べればわかる。
問題は,Rnd()で発生した数値が0.1200304で,4桁指定(結局6桁)であった場合,「0.1200」も4桁と扱ってしまうことだ。
この場合,「1,234.560」なんて数字が7桁として発生してしまうことになる。
このため,Val()をかませてある。
乱数を使っている為,時々しか不都合が発生せず,問題を追い詰めるのに,結局1日費やしてしまった・・・
息子にやってもらったところ,早速クレームが付いた・・・
整数同士のわり算の場合は,答えは必ず整数で割り切れるのだそうだ・・・
「珠算検定試験の出題にあたっての基本的考え方」(http://www.syuzan.net/shuan/kihon.htm)にはない,暗黙のルールなのだそうだ・・・
と,いうわけで,印刷イメージは,mondai.pdf