書くスキルの習得の準備としてのタイピングなら「かな入力」でも良いのでは?

今後、国語側でそれなりに書くことに時間をとるケースがでてきそうである。仮に手書きを回避したとして、文字入力は音声入力をさせるのだろうか?これに関連して、書くことの能力を身につける、という意味でのタイピングについて思うことを述べておく。

悪者にされがちなかな入力であるが・・・

ワーキングメモリを圧迫するローマ字 vs 記憶に時間がかかる「かな」

単純に「日本語で書くこと」を身につけるのであれば、ローマ字入力以外の入力方式のほうが優れているケースはある。これも「まさか」と思う人がいるとは思うが、ローマ字を扱うことが様々な意味で怪しいという環境はそれなりにある。

脳内ローマ字変換がワーキングメモリを圧迫しないでローマ字入力ができる人であれば、ローマ字入力で何の問題もない。現に、多くの優秀な人々は、ワーキングメモリが十分確保されているか、ローマ字入力を早い段階でワーキングメモリを圧迫しない形で身につけている。そのため、この問題そのものが表に出ることは多くない。しかし、そうでない環境も世の中には存在する。

かな入力はキー暗記が大変だという。しかし、逆に言えば、暗記がクリアできてしまえば問題はないということである。単純暗記は、たとえ学力が微妙でも、時間数を積み増して繰り返しの回数を増やすことで対処ができるので、まだなんとかなる可能性がある。

ある種のタイプのローマ字入力速度向上が止まる問題への解決する策が見つからない

タッチタイピングがある程度できるようになった後、入力速度を伸ばしていくにはある種の瞬発力を鍛える訓練が必要である。ローマ字の場合、タイピングを積み重ねることで脳内ローマ字変換能力と運動能力が向上してキー入力が早くなっていく。

しかし、この2つの能力が向上しにくいタイプについては、速度向上が頭打ちになってしまう。1分40文字(ほぼ手書きと同等)で頭打ちになるのであれば何も問題ない。しかし、1分20文字(ほぼ手書きの半分)あたりで止まられると困る。それでは、さすがに書くことに支障がでる。

ローマ字の瞬発力を向上させることが難しいケースへの決定的な解決策を、現状で私は見いだせていない(試行錯誤はしたし、ある種のケースの解決策は発見したが。)。これに対して、かなの抱える「暗記しにくい」という問題は「暗記時間を増やす」という明確な解決策が存在する。よって、かな入力が魅力的なのである。ゆっくり打っても、JISかななら1分40文字は問題なく出せるはずである(データはまだ収集していないが。)。

現状は、キー配列の暗記に時間がかけられないからかなが選択できない。キー配列の暗記に時間をかけられないのは「キーボード入力で行う活動の時間が少ないのだから、そのための準備時間はたいしてとれない。」というロジックによるものである。しかし、書くことの活動時間数が多く取ることになれば、このロジックは崩れる。書くことに時間を長く割くのであれば、書くことを快適にするための準備時間としてのキーボード入力の時間は長くとっても正当化される。

想定される文句1: かな入力は世間で使えない

かな入力は世間で使えないという反論がある。親指シフトNICOLA)ならともかく、JISかなは実際にたいていのPCで使えるのだからその反論はあてはまらないと思う。

私の場合は(サンプル数1)、本気で文章を考えて書く道具としては、ローマ字以外の入力方法で書いて、人の機械でそれ以外の適当な実務をするときはローマ字である。それでも十分かなの恩恵は得られている。

しかし、それでも色々という人がいるので別の反論も考えておく。

この国は、学校教育の文脈が実社会でどのように生かされるかは無視して良いということになってきた。長年国語を手書きでやってきているのもその現れであろう。汎用的な能力さえ学校で身につけさせれば、それ以外の能力は後から身につければ良いという考えであろう。

この理屈を使ってかな入力を弁護しておくと、かな入力が「社会では直接役に立たないが、書くこと、という汎用的なスキルを身につけるためには有用なスキルである。」となれば、別にかな入力そのものは社会で使えなくても良いということになる。そして、一部の生徒についてはその理屈が十分になりたつと私は考えている。

想定される文句2 : 時間をかけても得られるものが少ない

書く課題量が多くなってきたら、効率の良い早い配列が学校でのみしか使えないとしても、早い配列を覚えたメリットは大きくなる。課題量が多い場合、単位時間あたりの入力が少ないことで節約できる時間が大きくなることにつながる。

暗記はそんなに時間がかかるか?

私の半径3m以内でJISかなを指導した感じだと、世間でいうところの「暗記が大変」はあまりあてはまらないという実感がある。配列は、意外と覚えられる。

これは自分の経験とも整合的である。私も自分が中学のときにJISかなを覚えたときに「暗記が大変」だった記憶はあまりない(注: 私は暗記が超苦手)。3週間、早朝の30分程度にワープロ練習機で練習したら問題なく身についたはずである(もしかしたらそれより少なかったかも)。大学の1回生のときに親指シフトNICOLA)に切り替えたが、それでも「暗記が大変」だった記憶はあまりない。もちろん、最初の暗記する2週間ぐらいに不快な思いはあったが。

かな入力は暗記が大変、という問題はさっさと白黒をつけてしまいたい。少なくとも、かな入力にすることで増える暗記の時間を定量的に把握したい。このままでは「かな入力は無限に大変」となって、永久に選択肢から除外される。一度、小学生あたりを対象に、ローマ字とJISかなとNICOLAの習熟時間の計測をやってもらいたいものである。

4段を使った入力は確かに大変

ただし、必要な指の運動能力が身につけられるかに個人差はありそうである。特に、4段を使い切るという手の動きに慣れるのは大変そうである。

ただし、これは逆にメリットとも考えられる。Excelやプログラミングをやっていると、上部の数字や記号を避けると効率が悪い(または無理)。かなで4段を使い切る練習をすることでこれに慣れておくというのは悪い話ではない。

また、4段を使い切る練習はローマ字(英文)の入力にも生きてくる。3段ではごまかせていた自分のキーボード操作の弱点を、4段を使い切るということで明らかにできる、ということがありえるからである。ここで明らかになった弱点を改善することは、今後英文タイプやローマ字入力(に戻したとしても)をする上で確実に良い影響を与える。

同様の理屈でフリックや音声入力も認めても良いが

情報の時間でCUIを扱うならともかく、国語の時間であればフリック入力や音声入力も認めてあげても良いと思っている。ただ、この国は金がない。フリックや音声を保証するだけの金がない。よって、ある程度はキーボードで頑張らざるを得ない部分がでてくる。これは仕方がない。

環境を整えないと書くこと嫌いを量産するだけ

国語ではないが、私は書くこと自体はそんなに苦痛ではない。中学や高校のときからそうである。手書きでは書けないが、ワープロであれば書ける人である。質は問わないが。ただし手では書けない。国語の人に受ける文章も書けない。それにも関わらず書くことが苦痛にならなかったのは、タイピングと学校で書くことを強要されなかったことによる。

私は、多くの場合は、手書きの数倍のスピードで大量に文章を打ち込んでしまってから、直していく、というスタイルで書いている。それも時間を置いて何回か直すというスタイルを取る。これだからこそ書けるとも言える。一定以上の年齢になるまで、それ以外の書き方では私は書けなかった。特に手書きは無理だった。

もし、中学のときの私が手書きのスタイルで大量の文章を書く訓練を学校教育として強要されていたら、物を書くのが嫌になっていたと思う。そういうのだけは発生させて欲しく無いなと思わないでもない。

このまま、何の準備もなく手書きで書くことの時間数が増えたら、書くこと嫌いが量産されそうで恐ろしいな、と思う今日この頃である。

LuaTeXでルートの簡略化の計算問題の解答の作成(虚数のケースに対応)

以前の記事でルートの簡略化の問題を作るスクリプトを書いた。

もともと、これは二次方程式を解く問題の解答を自動生成するために作ったものである。よって、虚数にも拡張しておきたいという自然な欲求がある。そこで、虚数も混み(ルートの中身をマイナス)で作成したものをここに示す。

以下のような計算問題を考える。

f:id:baruku07:20180218222634p:plain

Luaの部分は次の通り。無駄に行数が多い・・・

-- 素因数分解。i番目の要素にiで何回割れるかが入る。結果として素因数のところ以外には全て0が入る。
function prime_division1(num) 
x = math.abs(num)
 ary={}
 if num>=0 then
   ary[1] =1
 else
   ary[1] = -1 -- 虚数の場合1を-1個かけられているという扱いをする。後の処理をきれいにするため。
 end
 for i=2,math.abs(num) do
   ary[i] = 0
    while x%i ==0 do
      ary[i] = ary[i] + 1
      x = math.floor(x/i)
    end
 end
 if num ==0 then --0の場合は1を0個のみ持つことにする。以下の処理がこれで不都合ないかは深く検討していない。(今後の課題)
  ary[1] =0
 end
  return ary --i番目にiが何回かけられている回数が格納されている。
end

-- 与えた数のルートの簡略化a\sqrt{b}を{a,b}の配列の形で返す
function kanyakuka(soinsuu_ary) ----i番目にiが何回かけられているかが格納されている配列を想定。
 a = 1
 b = soinsuu_ary[1] --実数なら1, 虚数なら-1
  for i=2, #soinsuu_ary do
   k = ary[i] -- 素因数iが何回掛けられているかを表している。
     if k>0 then
       a = a*i^(math.floor(k/2))
       b = b*i^(k%2) --割り切れる場合は0乗になって1がかけられて値不変。
     end     
  end
  return {a,b}
end

-- {a,b}の配列をa\sqrt{b}として出力。aやbには0以外の整数がくることが想定。
function root_exp(kanyakuka_ary)
  a = kanyakuka_ary[1]
  b = kanyakuka_ary[2]
  str = ""
  -- sqrt{b}の部分の生成
  function root_part(y) 
    str =""
    if math.abs(y) ~= 1 then -- +-1以外・ルート+-1は何も出力しない。
      str = "\\sqrt{" .. math.abs(y)  .. "}" -- 虚数の場合にマイナスを取り去る。実数ならそのまま。
    end
    if y<0 then --虚数であればをiくっつける
      str = str .. "i"
    end    
    return str
  end
  --aの部分の生成
  function int_part(x,y) 
    if (x==1 and y==1) or x~=1  then --1と整数部が1以外
      str =x
    else
      str =""
    end   
  return str   
  end
  str = int_part(a,b) .. root_part(b)
  return(str)
end

TeXの部分

\documentclass{ltjsarticle}
\usepackage{luacode}
\usepackage{amsmath}
\usepackage{tcolorbox}
\begin{luacode*}
-- ここに上のluaのコードが入る
\end{luacode*}

\newcommand{\gentoi}[1]{
 $\sqrt{#1 } $
 \begin{tcolorbox}[colframe=white,colback=white,width=2truecm,height=3pc,top=-2mm,visible] %
 \[
 \luaexec{tex.print(root_exp(kanyakuka(prime_division1(#1))))} 
 \]
\begin{gather*}
\end{gather*}   
 \end{tcolorbox}
}

\begin{document}

\begin{enumerate}
 \item \gentoi{-3}
 \item \gentoi{-16}
 \item \gentoi{-8}
 \item \gentoi{8}
 \item \gentoi{-1}
 \end{enumerate}
\end{document}

地味に書いていっているのでやたらに行数はかさんでいるがやっていることは単純で、ほぼ実数のみに対応するものと同じである。

  1. prime_division1で素因数分解
  2. kanyakukaでルートの外に出すべきものを外に出す
  3. root_expでa\sqrt{b}の形にする(aの文字列の生成部分とbの文字列の生成部分を内部で関数化して別々に考察している)

3.の部分に手を加えて虚数に対応した。いくつか簡単に説明しておく。

1. prime_division1

実数のみ考えるときに書いたものと同じく、配列のi要素に素因数iが何回かけられているかが入っている。ただし、マイナスの素因数に対応するため、マイナスの場合は1の個数が-1回かけられているとみなすことにした。

3. root_exp

a\sqrt{b}は色々と例外ルールがあり、それに対応する場合分けを書く必要がある。aがこうでbがこうで、とやっているとごちゃごちしていたので、aとbにわけて考えて後からくっつけることにした。

aについて

aについては、次のようにしている。

  • a=1以外のときは、そのままaを出力
  • a=1, b=1のときもそのままaを出力
  • それ以外のとき( a=1, b \neq 1 )のときは、何もしない。(aを省略)

\sqrt{b}について

bの絶対値が平方数のときは、ルートそのものを一切書かなくて良い。

\sqrt{b}に書くべきは符号を取り去ったものなので、bの絶対値をルートの中に書いたものを作ることにする。

さらに、b<0のときは、この部分にiを出力する必要があるので、そのようにしている。

キーボードの使用許可は手書きが厳しい人への配慮として機能しない場合がかなりありそう

高校の次期指導要領のパブコメ募集が出た。私の本業は情報であるが、国語の指導要領に特に注目していた。情報は、色々と理系風に高度化したがってるから、現状の何かを追い出さないといけない。その追い出し先が国語になりそうだったからである。期待としては、国語にメディアリテラシー風の話やプレゼンは丸投げ、あわよくば情報モラルは公共に丸投げ(これは失敗したが)というのがあった。期待通り、レポートとプレゼンは国語に丸投げに成功した。

私は社会科学出身の文系だが人文系ではないので、メディアリテラシーや文章・会話表現は教えたく無いのである。正確に言うと、教えられないことはないけど、国語教師の考える正しい国語に合わせて教えないとならないのがストレスなので嫌なのである。あとは、書くことの単発の指導ぐらいなら情報の人でもできるけど、基礎から積み重ねていって技能を習得させる指導については、やはり国語の方がプロなので効率が良い。よって、情報から消えてくれたほうが楽しい。

国語でPCが許されたとしても文字をキーボードで入力できるのか?

次期要領の国語の書くことは、期待以上であった。最もうれしかったのは、書くことの時間数をきちんと縛ってくれたことである。それも、「現代の国語」だけでなく「論理国語」までそうなった(追記注 : 現行でも国総は縛ってるけどスルーされている。古典ともセットなのでどうとでも逃げやすい。)。これで、学習指導要領を盾に「レポートとプレゼンは国語の仕事なので私は知りません(国語の免許はもってないし)」と言えるのである。嬉しい限りである。

しかし、押し付けられた国語は色々と大変であろう。例えば、この時間数で国語で書くことに取り組ませるとなると、手書きではきつい生徒も出てくると思われる。PCの使用を許可せざるを得ないケースもありそうである。だいたい、例示されている活動に「画像」というキーワードがちらっと見えた。画像を含む文章を手書きで扱うとも考えにくい。PCでやると考えるのが自然である。また、いくつもの例示されてる活動も、これは普通は手でやらないよな、というものが多数ある。

さて、今でも先進的な方々は、障害等に対する配慮としてPCによる文字入力の許可を要求している。しかし、それが仮に許されたとして、キーボードはそんなに簡単ではないぞと心の中で思っている私がいる。

以下、詳細に踏み込むことを避けるためにわかりにくい書き方になるかもしれないが、書ける範囲で思うことを書く。

仮に配慮を要する生徒に関してキーボード使用を認めたとしてですよ。本当にその人達タイピングもできるのか?私が見てきた傾向として、手書きが苦手な生徒は、タイピングの習熟も遅い傾向がある。あるいは、何らかの指導の工夫がないと伸びていかないという傾向もある。もちろん、例外も相当数あるので、やらせてみる価値は十二分にある。

タイピングの習熟が難しいケースに関しては、業務で様々なメニューを試してきた。それによって効果が上がったケースもそれなりにある。しかし、どうしようもないものはどうしようもないケースも存在することを痛感している。

超重症患者は手がまっすぐに置けない・指の曲げ伸ばしが難しい

習熟が遅いを通り越してしまったケースに共通する問題としては、キーに対して平行に指を置くことが難しい、というのがある。また、指を適切に曲げ伸ばしできないという問題も併発していることがほとんどである。この問題以外は時間をかけて、症状に応じた適切なメニューを実行させれば、クリアできることは実感している。

キーに平行に対して指が置けないケースに対して、安物のエルゴノミクスキーボードを試したケースもある。この方法で改善したケースもある。使ったキーボードが安物だったため、傾斜が適切でなく、それで合わないでだめとなったケースもあったが。

できないケースの様子を観察している感じだと、左右分離型のキーボードで自分に合った角度をつけてあげれば、なんとかなりそうという実感が得られている。しかし、お値段が2万円弱である。今の私の経済状況では試せない。

うまく行きにくい情報がもう少し表に出てきて欲しい

最近、私が思うことに、タイピングの練習の効果が上がりにくいケースが、もっと積極的に表に出てきて欲しいというのがある。今、インターネット上に落ちている情報の大半は「タッチタイピングは、適切な方法で適切な期間練習をすれば誰でも簡単にできる。最大のハードルは、練習方法の情報が行き渡ってないことと練習時間の確保である。」といったものである。私も数年前まではそれを信じていた。しかし、それがあてはまらないケースをそれなりに経験した今は、そんな無邪気なことは言えない。

こういった、タイピングは「いかなる人にも」簡単、という情報のみが氾濫する状況で困ることは、タイピングができないのは指導法が悪いとか本人の努力が悪いとかいうことになってしまうことである。困難な人には困難なんだから温かく見守ってあげないとね・・・

今は、タイピングをさらっと指導できるケースしか表に出てきていないと思われる。さらっとできないケースを無理して指導するインセンティブがゼロだからである。やらせていなければ、何の問題も表に出るわけもない。しかし、書くことの時間数が増えてきたら、さらっとタイピングが指導できないケースでもせざるを得ないシーンもでてきそうである。そうすると、もう少しタイピングが困難なケースが表に出てくるのではないかと期待している。

どうせ骨抜きか手書きかになりそうだけど

もっとも、国語の件は、ここまで過激に書かれたら「どうせやるの無理だから全部骨抜き」というのが、今のところの私の予想の本命である。

ただ、それでも「建前としては国語の責任」と言い切れる状況ができたことだけで私は十分(だけど社会全体としてはどうかと思うが)。

追記(2/18)

現在でも国総は書くことの時間数の明示はあった。冒頭のかき回しだと、現在は時間数縛りがない感じになるので良くない。確かに見た記憶もある。

情報の授業をするために、国総の教科書もそれなりに参考にしたことがあった。国総では、現行でも確かにそれなりに書くこと・話すことは存在するのは把握していた。ただし、指導要領本文側の縛り方が薄かったようなイメージがあったので、それに比べたらきつく縛ったなというイメージである。

そして、現代文Bでは書くことはスルーしても問題ないようになっている。さらに、現行では指導要領側(解説はともかく)に活動の例示もこんなにない。さすがにこの書き方では国語以外の人に「レポートとプレゼンは国語の仕事だ」とやるのは難しいのである。国語の先生に対してはは通用するものの、そういうのが通用する国語の先生は非常に優秀な方なので、そもそも最初から敵対しない。

現在の書き回しでは、書くことや話すことをスルーした国語をあまり責められないようなイメージがある。特に国表を開講していない場合はそうである。ぱっとみ、新の書き回しなら、これならレポート・プレゼンは国語の責任に完全にできるという印象を持った。よって、冒頭の書き回しである。

正直、国語がやるかどうかという実態はどうでも良いのである。情報が今後わけわからないことを教えたときに(絶対にそうなる。あんなの生徒が理解できるわけない。これはそのうち詳しく論じる。)、「もっとわかりやすく楽しいことを教えろ」とか「実社会で役立つレポート・プレゼンを教えろ」という声が絶対にでるに決まってる。そのときに、対生徒・対その他いろいろを突っぱねたいのである。(いつまでこの仕事するかわからないけど)私が、本来教えるべきことでないことについて、責任逃れできればそれで良いのである。

(生徒が理解しにくい)統計やモデリングを教えれば数学だと言われ、(生徒がやった感がでる)プレゼンを教えるのが情報だというの屁理屈はさっさと却下したいのである。

情報Iがどのようなものになっても「プレゼンは情報で面倒みろ」というわけわかめな理屈は出てくると思われる。それをはねのけようと思ったら、情報科の学習指導要領を盾に抵抗するのは弱い。誰でもわかる、主要教科の国語の指導要領を盾に取るしかない。その盾が大幅強化されたというのが今回の私の印象である。この盾であれば誰とも戦えると。

LuaTeXでルートの簡略化の計算問題と解答を生成

昨日の2次元方程式のファイルを、ルートの簡略化が発生するケースに拡張したいと考えている。その一歩として、ルートの簡略化をするためのコードを書いた。

結果として、次のような計算問題と解答までは作れるようになった。途中式はまだ。

f:id:baruku07:20180215224623p:plain

Luaのコード

-- 素因数分解。i番目の要素にiで何回割れるかが入る。結果として素因数のところ以外には全て0が入る。
function prime_division1(num) 
x = num
ary={}
ary[1] = 1 --1つ目の要素に1を詰めておかないと、2,3のときに正しい値を返さない
 for i=2,num do
   ary[i] = 0
    while x%i ==0 do
      ary[i] = ary[i] + 1
      x = math.floor(x/i)
    end
 end
  return ary
end

-- 与えた数のルートの簡略化a\sqrt{b}を{a,b}の配列の形で返す
function kanyakuka(soinsuu_ary) 
 a = 1
 b = 1
  for i=2, #soinsuu_ary do
   k = ary[i] -- 素因数の個数
     if k>0 then
       a = a*i^(math.floor(k/2))
       b = b*i^(k%2) --割り切れる場合は0乗になって1がかけられて値不変。
     end     
  end
  return {a,b}
end

-- {a,b}の配列をa\sqrt{b}として出力。
function root_exp(kanyakuka_ary)
  a = kanyakuka_ary[1]
  b = kanyakuka_ary[2]
  if    b == 1 then
    tex.print{a}
  elseif a == 1 then --これを最初のif節にすると\sqrt{1}が出力になるのでダメ。
    tex.print("\\sqrt{" .. b .. "}")
  else
    tex.print(a .. "\\sqrt{" .. b .."}")
  end
end

TeXのコード

\documentclass{ltjsarticle}
\usepackage{luacode}
\usepackage{amsmath}
\usepackage{tcolorbox}
\begin{luacode*}
--ここに上のluaのコード
\end{luacode*}

\newcommand{\kanyakuka}[1]{
 \luaexec{root_exp(kanyakuka(prime_division1(#1)))}  
}

\newcommand{\gentoi}[1]{
$\sqrt{#1}$
 \begin{tcolorbox}[colframe=white,colback=white,width=3truecm,height=4pc,visible] %
 \[
 \kanyakuka{#1}
 \]
 \end{tcolorbox}
}

\begin{document}

\gentoi{4}
\gentoi{12}
\gentoi{121}
\gentoi{128}

\end{document}

やっていることは

  1. prime_division1で素因数分解(配列で返す)
  2. kanyakukaで各素因数ごとにx\sqrt{y}の形を作り、xの部分のみををかけたものとyの部分をかけたものを作る。(と結果としてa\sqrt{b}の形が得られる)
  3. 2.をroot_expでtexでa\sqrt{b}の形で表現する。

である。以下1.と3.について簡単にコメント。

1. prime_division1で素因数分解

素因数をキーに、個数を値にしたテーブルを作るのが自然である。しかし、テーブルのキーは文字列として扱われるかもしれない(調べていない)。そのあたりを調べたくなかったのでこのように書いた。

大きい数を扱うつもりはない・速度は気にしない、ということなので、nまでの全ての整数を並べた配列を作っておき、そこに素因数の個数を格納する方針を取った。

2で割って割れるだけ割る -> 2割った回数を記録 -> 3で割って割れるだけ割る -> 3で割った回数を記録なので、単純に書ける。

2/16修正

prime_division1のループの終端をmath.floor(num1/2)をnumに修正。それに合わせて上の文も\sqrt{n}までをnまでに修正。最後の最後で、たぶんroot{n}までで大丈夫だろうと良く考えずにやったのが大うっかり。

素数の場合で考えると、明らかに自分自身の数に素因数の個数1が入らないとだめなので、自分自身の数までループは回すしかない。

3. root_exp

整数になるケースも含めて対応をする。1\sqrt{b}やa\sqrt{1}という表現はありえないので、それを回避するために簡単な場合分けを書いている。

感想(余談)

この問題も、emathにあるような気がしないでもない。うまくみつけられないが。

なお、素因数分解の問題もこれを少し工夫すればいけそうである。ただし、素因数分解はemathに既製品はある。

この問題も、一応は自作する価値が私にとってある。途中式を、素因数分解の筆算を横に並べるという形では書きたく無いということがあるからである。おおざっぱに、九九で分解して、それをさらに細かく分解していくというスタイルでの途中式を書きたい。

LuaTeXで解の公式の問題(実数解・ルートが残る・ルートの簡略化なし)の問題と解答を作る

昨日の話の続きのようなものである。

今度は2次方程式の問題のうち、解の公式を使って解くものの問題と解答を生成できるものを作った。今日も、LuaTeXで強引にやっている。そんなに無理してTeXを使わず既製品を使えという話ですが・・・ネタだから問題ないということで。

次のようなものを作りたい。 f:id:baruku07:20180214204248p:plain

以下がソースである。まずはLua

--- 文字式の係数の処理
function add_plus_dimzero(num) --定数項
  if num > 0 then
     return "+" ..  num
  else 
    return num
  end
end

function add_plus_dimhighest(num) --最高次
 if num == 1 then
   return ""
 elseif num == -1 then
   return "-"
 else
   return num
 end
end

function add_plus(num) -- 定数項と最高次以外
 if  num == 1 then
   return "+"
 elseif num ==-1 then
   return "-"
 elseif num > 0 then
   return "+" .. num
 else
   return num
 end
end

function gen_polyform(ary) -- 係数の配列(n次から並んでいる)から多項式を生成
  str =""
  -- n次(最高次)の処理
     n = #ary -1 
     str = str ..add_plus_dimhighest(ary[1]) .. "x^ " .. n
  -- n次, 1, 定数項以外
  for i=2, #ary -2 do
     n=n -1
     str = str ..add_plus(ary[i]) .. "x^" .. n
  end 
 --1次式の処理(x^1はだめだから別枠)
    str = str .. add_plus(ary[#ary - 1]) ..  "x"
  --定数項
    str = str .. add_plus_dimzero(ary[#ary])  
  tex.print(str)
end

---2次方程式の解の公式の形(bが偶数や虚数のケースなども視野に入れて、解答の形を整形するための関数は別に用意することにする。)
function kai_form(ary)
  tex.print("\\frac{" .. ary[1] .. " \\pm \\sqrt{" .. ary[2] .. "}}{" .. ary[3]  .. "}")
end

-- 文字式にマイナスの数値を入れるときの括弧の追加
function add_minus_kakko(num)
   if num<0 then
     return "(" .. num .. ")"
   else
     return num 
   end
end

-- 解の公式に単純に数値を代入しただけの途中式を作る
function dainyushiki(ary)
  arystr ={}
  for i=1, #ary do
    arystr[i] = add_minus_kakko(ary[i])
  end
  bunshi = "\\frac{-" .. arystr[2] .. " \\pm \\sqrt{" .. arystr[2] .. "^2-4\\cdot" .. arystr[1] .. "\\cdot" .. arystr[3] .. "}}"
  bunbo = "{2 \\cdot " .. arystr[2]  .. "}"
  tex.print(bunshi .. bunbo)
end

-- 計算を実行して解を出力する(ただし、判別式が平方数・ルートの簡略化が発生・虚数が発生するケースには対応していない)
function h(ary)
  bunsi1 =  -ary[2]
  disc      = ary[2]*ary[2] - 4*ary[1]*ary[3]
  bunbo  = 2*ary[1]
  kai_form({bunsi1,disc,bunbo})
end

TeXの部分。

\documentclass{ltjsarticle}
\usepackage{luacode}
\usepackage{amsmath}
\usepackage{tcolorbox}
\begin{luacode*}
%ここに上のluaのコードが入る
\end{luacode*}

\newcommand{\gentoi}[3]{
 $\luaexec{gen_polyform({#1,#2,#3})} = 0$
 \begin{tcolorbox}[colframe=white,colback=white,width=6truecm,height=8pc,visible] %
 %widthの設定の際には、(-)が幅を取ることを想定して設定する。
\begin{gather*}
  x = \luaexec{dainyushiki({#1,#2,#3})} \\
  x = \luaexec{h({#1,#2,#3})}
\end{gather*}   
 \end{tcolorbox}
}

\begin{document}

\begin{enumerate}
 \item \gentoi{1}{3}{-5}
 \item \gentoi{2}{7}{-7}
 \item \gentoi{1}{-7}{3}
 \item \gentoi{3}{5}{-5}
\end{enumerate}
\end{document}

特に説明するべき点もない。

Luaのコードのほとんどは多項式の生成のためのものである。

多項式の生成部分はemathのprPolynomialを使えば3秒である。しかし、このためだけにemathを読み込ませるのはあまりに重すぎる。よって、簡単に自作した。最終的には、素のoverleafで使えるようにしたい、という思いがあるので、多項式を作る関数を自作した。

途中式色々

途中式を触りたいので、このように自作をしている。これぐらい書いておけば少々さわれば思い通りの式が作れる。

例えば、私はb2の部分の代入は、符号を書かずに(どうせ2乗だから)いかなる場合も+と思い込んで計算せよと指示している。よって、途中式のマイナスは取りさってしまいたい。-(-b)も、それぐらいひっくり返すだけなんだから暗算しろという。

場合によっては、いきなりb2を計算した値を書けとか、4acぐらいも暗算して書けという指示をすることもある。その場合は、1式目に-(-b)・b2・4acの計算した結果が入る。

学力層が高く無い集団を教えるのであれば、b2の計算結果・4acの計算結果・2aの計算結果を書いた式をもう一行作ることもありえる。

道はまだ遠い

まだ、対応すべきケースが様々ある。

  • 虚数解が発生するケース
  • ルートの中が平方数(この場合は因数分解で解答を作るようにする)
  • ルートを簡略化するケース
  • 偶数のケース

いろいろと面倒そうなので、暇なときにやりたい。

係数の設定

問題を作るときには、適度に手計算できるように係数を設定する。この「適度な」を適切に定義し、その「適度な」係数パターンの全パターンを何らかの形で列挙したものを持っておきたい。そうすれば、そこから代入して問題を作るだけである。これも今後の課題である。

LuaTeXで簡単な2次方程式の問題と解答を作る

中学生的な数学を教えていると、ワンパターンの2次方程式を解く練習を大量に作りたいということがある。

LuaTeXを使って作ってみた。2次の係数は1・解は0か2解を足して0になる以外の整数・異なる2解を持つケースに対応している。前の2次関数のときと違い、方程式の1次の係数が-1と1になるケースについても対応した。

f:id:baruku07:20180212205953p:plain

以下がluaのコード。(色分けのためブロックをわけた)

function add_plus(num) -- +記号をつけて出力。定数項で使用。
 if num > 0 then
  return "+" .. num
 else
  return num
 end
end

function add_plus2(num) -- +記号をつけて出力・係数1を無視する。定数項以外で使用。
 if  num ==1 then
 return "+"
 elseif num ==-1 then
 return "-"
 elseif num > 0 then
  return "+" .. num
 else
  return num
 end
end

function h1(ary) --問題文の式
 x1_plus_x2 = ary[1] + ary[2]
 x1_times_x2 = ary[1]*ary[2]
 tex.print("x^2" ..add_plus2(-x1_plus_x2) .. "x" ..add_plus(x1_times_x2) .."=0")
end

function h2(ary) --因数分解の式の生成
 a = add_plus(-ary[1])
  b = add_plus(-ary[2])
 tex.print("(x" ..  a .. ")(x" ..  b ..")=0" )
end

以下がtexのソース。

\documentclass{ltjsarticle}
\usepackage{luacode}
\usepackage{amsmath}
\usepackage{tcolorbox}
\begin{luacode*}
%%ここに上のluaのコードが入る
\end{luacode*}

\newcommand{\gentoi}[2]{%
$\luaexec{h1({#1,#2})}$
\begin{tcolorbox}[colframe=white,colback=white,width=4truecm,height=5pc,left=-5truemm,top=-3truemm,visible]
\begin{gather*}
   \luaexec{h2({#1,#2})}\\
   x =  #1, #2
\end{gather*}
\end{tcolorbox}
}

\begin{document}
\begin{enumerate}
 \item \gentoi{3}{5}
 \item \gentoi{6}{-5}
 \item \gentoi{5}{-6}
 \item \gentoi{-7}{-5}
\end{enumerate}
\end{document}

この問題については、既製品は色々とある。既製品に対する利点は、細かい部分を自分で思うようにできるというだけである。定型パターンで対応できない集団を教えているときには、この点が大きい。

自分が定型的なパターンで対応できない集団を教えているときには、自分で自動生成をやろうと試行錯誤していた。

この手の2次方程式の生成は、Rubyで文字列を生成してから貼り付けをしていたこともあった。Rubyの機能を生かして、2解の候補の配列候補を生成しておいて、それからランダムに選んでプリントに貼り付けたこともある。しかし、コピーアンドペーストもだるいし、スクリプトファイルをどこに置いたか行方不明にもなることがある。TeXで済むならそれが良い。

LuaTeXで2次関数の頂点を計算する問題の解答を作る(2次の係数は1, 頂点整数のケース)

数学の授業を持っていると、自分の思う通りの途中式で解答を作りたくなることがある。特に、持っている学力層によっては問題集そのままの解答は使えないので、必然的にそうせざるをえない。解答は数値だけを見て、問題を解く方法は授業で教えた方法に読み替える、という行為は、相当に高度な行為なのである。

問題・解答の生成で面倒なのは、単純反復系・同系統の問題の大量作成である。学力層によってはこの作業が頻繁に発生する。この作業はそれなりに骨が折れる。解答をミスすることも良くある。

同系統の問題を大量生成するとき、TeXのマクロで途中式に数字をはめ込むぐらいのことは今までもしていた。しかし、計算もやってくれると助かる、と思うことはよくあった。そこで、Luaの力を借りて計算をしてみる方法を考えることとした。

手始めに2次関数の頂点を求める問題とその解答の作成を自動化してみた。現状は、2次の係数が1で頂点が整数になるケースのみしか扱えない。しかし、とりあえずは動くものができたので紹介。

f:id:baruku07:20180212160040p:plain

以下はソース。luaの部分。(色分けをさせるためにあえてブロックをわけている)

function add_plus(num) -- +記号をつけて出力
 if num > 0 then
  return "+" .. num
 else
  return num
 end
end

function calc_choten(ary) --頂点の計算
  ary1 ={}
  ary1[1] = -ary[1]/2
  ary1[2] = -(ary[1])^2/4 + ary[2]
  return ary1
end

function h1(ary) --問題文の式
 tex.print("x^2" ..add_plus(ary[1]) .. "x" ..add_plus(ary[2]) )
end

function h2(ary) --途中式1行目
 tex.print("(x" .. add_plus(ary[1]/2) .. ") ^2-" .. math.abs(ary[1])/2 .. "^2" .. add_plus(ary[2])   ) 
end

function h3(ary) --平方完成済の式
 choten_x = calc_choten(ary)[1]
 choten_y = calc_choten(ary)[2] 
 tex.print("(x" .. add_plus(-choten_x) .. ") ^2" .. add_plus(choten_y)  ) 
end

function h4(ary) --頂点の座標の出力
 choten_x = calc_choten(ary)[1]
 choten_y = calc_choten(ary)[2] 
 tex.print(choten_x .."," .. choten_y)
end

texの部分。

\documentclass{ltjsarticle}
\usepackage{luacode}
\usepackage{amsmath}
\usepackage{tcolorbox}
\begin{luacode*}
%%この部分に上のluaのコードを挿入
\end{luacode*}

\newcommand{\gentoi}[2]{%
$y=\luaexec{h1({#1,#2})}$
\begin{tcolorbox}[colback=white,colframe=white, width=7truecm,height=9pc,visible]
  \begin{align*}
   y &= \luaexec{h2({#1,#2})} \\
      &= \luaexec{h3({#1,#2})} 
  \end{align*}

よって、頂点は点$(\luaexec{h4({#1,#2})})$となる。
\end{tcolorbox}
}

\begin{document}
以下の2次関数のグラフの頂点の座標を求めよ。
\begin{enumerate}
 \item \gentoi{-4}{12}
 \item \gentoi{2}{-5}
 \item \gentoi{8}{6}
 \item \gentoi{-6}{-6}
\end{enumerate}


\end{document}

本体については、特に説明を要する部分はない。

なお、tcolorboxを使っているのは次の意図。

  • widthとheightの指定
  • visibleとinvisibleで問題と解答を切り替える

レイアウトは手抜き。問題の生成の例をみせるためだから。実際のプリントはもう少し丁寧にレイアウトして作る(たぶん問題を横に2つ並べると思う。)。

途中式は私の好みである。学力層によって、ここは書き分けるべきである。それをしたいからこそ、自分でマクロを書いているとも言える。いちおう、意図。

  • 2で割る式は省略。それはさすがに何をやっているか類推できる。
  • 1行目の2乗を引く式はあえて計算していない(()内の第2項と同じものの絶対値の2乗を引いている、ということを見せる。)
  • 2乗の計算結果と定数項との足し算は省略(学力次第ではこの行も必要となる。)

もう少し拡張したい

配列から多項式の式を組み立てる関数を書けば、2次の係数が-1のケースは扱えそう。2次の係数が2以上のケースは、途中式が変わってくるので手間が少しかかりそう。

頂点分数ぐらいまでは対応させたいけどな・・・

でも、このプリントを使うこともないのでいつになるかわからない。。。