おもこん

おもこんは「思いつくままにコンピュターの話し」の省略形です

電卓プログラムにRaccとStrScanライブラリを使用

今回の電卓プログラムは、最近投稿した計算結果が分数になる電卓とは別のプログラムで、小数を用いる普通のタイプの電卓です。

電卓プログラムCalc

このプログラムCalcは以前GitHubに置いてあったものですが、最近アップデートしました。 このアップデートは大きなもので、ほとんど書き換えといって良いものです。 ポイントは、Rubyの標準添付ライブラリのRaccとStrScanを使ったことです。

Raccとは?

Raccは有名なコンパイラコンパイラYaccRubyバージョンで、Rubyに同梱されています。 コンパイラコンパイラは「コンパイラを作成するコンパイラ」という意味ですが、古い言葉です。 今ではパーサ・ジェネレータの方がよく使われます。 これは「構文解析プログラムを生成するプログラム」という意味です。

RubyのドキュメントにはRaccの項目がありますが、ほとんど何も書かれていません。 作者のウェブサイトにドキュメントがあるので、それが参考になります。

Raccについては、別にブログ記事を書きたいと思いますので、ここでは説明を略します。

StrScanとは?

StrScan(ライブラリ名は小文字)は文字列を高速にスキャンするライブラリです。 StringScannerクラスのインスタンスを作成するときに、対象となる文字列を引数に与えます。 そのインスタンスに対してscanメソッドを使い、スキャンします。 例がRubyのドキュメントにあるので、それをご覧になれば良くわかると思います。

これを使うと、字句解析プログラムを簡単に作ることができます。 もともとRubyには正規表現があるので、字句解析プログラムを作るのは簡単ですが、このクラスはそれを高速に行うことができます。 このライブラリについても後日別に記事を投稿しますので、詳しいことはそちらをご覧ください。

電卓プログラムについて、再び

電卓プログラムはCalcという名前で、GitHubに登録してあります。

Raccを使ったので驚くほど簡単に、短くなりました。 今まで構文解析Rubyで書いていたのに比べると、格段に楽です。 Raccのソースファイルはたったの84行です。

Raccをどのように使うかは、このレポジトリのraccフォルダの下にあるdoc.mdを見てください。

また、このアップデートからは、gemのスタイルを取るようにしました。 しかし、Rubygemsには登録していません。 すでに同名のgemが登録されているので、別名にしないと登録できないのです。 電卓プログラムはいろいろなものが既に普及しているので、Rubygemsに入れるまでもないということで登録を見送りました。

ただ、この電卓は三角関数などもサポートしているので、便利ではあります。 興味がでたら、ぜひ使ってみてください。

計算結果が分数になる電卓

電卓の答えは小数になる

皆さんよくご存知のことですが、電卓で割り算するとその答えは(割り切れなければ)小数になります。 物差しで長さを図るときには、2.3cmのように小数になり、分数にはなりません。 ですから、電卓が小数を使うことは、理にかなっているといえます。

数学では小数が問題になる

ところが、数学では小数が問題になります。 というのは、割り切れないときに小数はその数を正確に表すことが難しいのです。 例えば「サンブンノイチ」

 \displaystyle \frac{1}{3}=0.3333 ...

右辺をどこかで四捨五入すると誤差が生じます。 したがって、その数を正確に表すには無限小数を使わなければなりません。

では無限小数を使えば問題がなくなるかというと、そうではありません。 これでも困ったことが起こります。 それは、0.9999...という無限小数です。 これは1に等しいことが知られています。

 0.9999 ... = 1

そうなると、ひとつの数字が、1と0.9999...という2つの表現を持つことになります。

これらの問題は小数を用いることからきているのです。 それを避けるために数学では分数を主として用います。

分数の計算を分数でしたい

そうなると、分数の計算を分数のまましたくなります。 いつもは小数で良いけれど、時々は分数も使いたい。 でも電卓は分数には対応していない。

そこで、分数を使えるプログラムをさがすと、以前紹介したmaximaなどがそれにあたります。 それで十分ではあるのですが、Rubyで分数をサポートする電卓を作ってみました。

ポイントは式の構文解析

分数の計算自体はRubyのRationalクラスがサポートしています。 ですので、プログラム中で分数計算するのは何も問題ありません。 ポイントは入力された文字列を構文解析して、プログラムに「式として理解させる」ことです。 そのために、例えば1/3+1/2という式を

     +
   /   \
  /     /
 / \   / \ 
1   3 1   2

図のように木構造のデータに直し、それを計算していきます。 ごく簡単に要点をまとめると

この3つになります。

GitHubのレポジトリ

プログラムをGitHubのMath_Programsというレポジトリにアップロードしてあるので、詳細はそちらをご覧ください。 なお、該当のプログラムは

lib/math_programs/acr.rb

です。

このプログラムはgemの形式になっているので、gem buildでビルドして、gem installでインストールすると、コマンドラインから使うことができます。 実行してみましょう。

$ mp23 acr 1/2+1/3
5/6

このように、答えが分数になります。 このレポジトリには他に不定方程式、分子が1になる分数の和で表す問題、拡張テンパズルも入っています。 これらは以前このブログでとりあげたので、そちらも参考になると思います。

拡張テンパズル

YoutubeのQuizKnockを見ていて、面白い問題を人間とコンピュータ(のプログラムを作る人間)が勝負していました。 動画はもちろん面白かったのですが、このパズルを解くプログラムを自分でも作ってみたくなりました。

このパズルは例えば次のようなものです。

数字1, 2, 3, 4, 5と四則演算(加減乗除のこと)をつかい、その式の計算結果が20になるような式を見つけよ。

答えは複数ある可能性がありますが、ひとつ見つければ良いことにします。 例えば、

 3\times 5-1+2+4=20

はひとつの答になっています。

パズルの名前

このパズルは有名なのでしょうか?またその呼び名はあるのでしょうか? ネットを探してみると、「テンパズル」または「メイクテン」というのが、これに似ています。

ただし、テンパズルは与えられる一桁の数字が4個で、計算結果は10に固定されています。 計算結果が10ということが「テン」パズル、あるいはマイク「テン」の元になっているようです。

拡張テンパズル

このパズルの条件を拡張します。

  • 計算式に使う数字は4個でなくても良い。2個以上なら良いものとする
  • 計算式に使う数字は二桁以上でも良い。要するに自然数なら良い
  • 計算結果は10でなくても良い

これをここでは「拡張テンパズル」と呼ぶことにします。 拡張テンパズルを解くプログラムをRubyで作ってみました。 GitHubにすでにアップロードしてあります。

(9/29 追記)

このレポジトリのプログラム全体が大きく変更されました。 そのため、以下の記事とレポジトリの説明文書が異なる部分があります。 その場合は、レポジトリ内の文書の方が正しいです。 また、変更後のプログラムはgem形式になっていて、requireするときは、ライブラリ全体を対象に行います。

require 'math_programs'

下記のプログラムのrequire_relative文は、このように置き換えるなどしてみてください。

(追記 終わり)

プログラム名の「e10p.rb」がextended TenPuzzleからきています。 このプログラムはライブラリであり、メインプログラムを作る必要があります。 demo.rbがそのような例になっているので、参考にしてください。

プログラムの実行

プログラムを実行するためのメインプログラムの例を示します。

require_relative "e10p.rb"

numbers = ARGV.dup.map{|s| s.to_i}
sum = numbers.pop
puzzle = E10P.new(numbers, sum)
print "#{puzzle.solve}\n"

これを実行するときに、引数に「式に使う数字」と「合計」を空白区切りで指定します。 例えば、式に使う数字が11, 20, 33で、合計が42とすると、

$ ruby main_program.rb 11 20 33 42
33-(11-20)

このように答えが表示されます。

テンパズルもやってみましょう。

$ ruby main_program.rb 2 3 5 8 10
5*(8-2*3)

面白いのは、分数が一度出てくるような例があることです。

$ ruby main_program.rb 1 1 9 9 10
9*(1+1/9)

プログラムの仕組み

例 2,4,5,6から10を作る

答えの一例は

 5\times(2\times 4-6)

です。 これは木構造で表すと

  *
 / \
5   -
   / \
  *   6
 / \
2   4

となります。 一番下の階層は2*4になっています。 この結果は8ですが、これから、この問題は、8と5, 6の3つで10になる計算を見つければ良いことになります。 もちろん、最初から2と4を組み合わせれば良いことは分かりませんから、4つの数字から2個をとる順列を生成し、虱潰しに探していきます。

数字がひとつ減ったので、今と同じ方法を用いると、次は数字が2つになります。 このようにして数字を減らしていって、計算結果が10になる場合を見つければ良いことになります。 これは、再帰呼出しです。

GitHubのプログラムでは、solve_realというメソッドがそれに当たります。

この問題はプログラム化が結構難しいと思いますが、Rubyのクラスを導入して木構造を作ると短くまとめることができます。

数式処理アプリケーションMaxima

Maximaとは

Maximaは古く歴史のあるアプリケーションですが、現在でも開発が行われています。 いわゆる「数式処理」をするアプリです。 電卓やPCの計算は数字に対するもので、整式などは扱えません。 例えば、次の式を展開する計算はできません。

 (x+1)(x+2)

このような計算をすることを「数式処理」といいます。 Maximaは数式処理をするアプリです。 詳しくはドキュメントを参照してください。 ここでは簡単な例のみ取り扱います。

2つのMaxima

Ubuntu Softwareというアプリケーションを開き「Science」ボタンからMaximaを探すと

の2つがあります。

どちらもMaximaなのですが、WxMaximaはGUIに対応しています。 1番目のMaximaは端末からCUIベースで操作します。

Ubuntu Softwareから簡単にインストールすることができます。

Windows版もあります。 ダウンロードサイトの説明を見てダウンロードしてください。

式の展開と因数分解

Maximaはコマンド、引数、セミコロンがまとまりになります。 ここでは2つのコマンドを試してみましょう。

  • expand: 引数で与えられた式を展開する
  • factor: 引数で与えられた式を因数分解する

式は、四則(+-*/)と累乗(^)が可能です。  x^2+2x+3は「x^2+2*x+3」と書きます。

まず、Maximaを起動して、展開、因数分解した画像を見てください。

Maxima

CUIベースなので、指数が同サイズのフォントで1行上に現れるので見にくいです。 しかし、きちんと展開、因数分解ができていることがわかると思います。

なお、乗算記号(*)とセミコロンを忘れないようにしてください。 セミコロンを忘れると、次の行に入力が繋がりますので、そこでセミコロンを打つと計算をしてくれます。 終了するときには

quit();

とタイプしてください。

次にWxMaximaで展開と因数分解した画像です。

WxMaxima

こちらはGUIベースなので多少見やすいと思います。

終了はメニューからできます。 Maximaのようにquitコマンドを使うと、GUIの背後で動いているmaximaが終了してしまうので注意してください。

まとめ

Maximaは豊富な機能を持っているので、興味のある方はウェブサイトを調べてみてください。 自分は展開や因数分解のチェックで使うことが多いです。 私は整式の手計算のミスが多いので、助けられています。

数式処理ソフトでは、一時期Mathematicaがウェブで語られていましたが、こちらは有料です。 現時点でMathematicaウェブサイトを調べたところ、デスクトップ版を家庭・趣味用で購入すると387ドル(145.97円×387=56490.39円)です。 円安なので高くつきますね。 他に教育用などの別のライセンスがありますから、購入を検討する人は調べてみてください。

Maximaは無料で使うことができるので、手軽だと思います。

WindowsにImageMagickとRMagickをインストール

Windowsで画像処理を行うため、ImageMagickをインストールします

ImageMagickのインストール

  • ImageMagickのウェブサイトをブラウザで開く
  • タイトルバーのダウンロードボタンをクリック(他に広告のダウンロードボタンもあるが、それは違うので要注意)
  • 下の方にWindowsインストーラがある。「ImageMagick-7.1.1-15-Q16-HDRI-x64-dll.exe」をクリックしてダウンロード。 PCの能力に応じて別のインストーラを選択してもよい
  • インストーラの指示に従ってインストール。 途中で「Install development headers and libraries for C and C++」にチェックを入れる。 これはRMagickを後にインストールするときに必要なため

テスト

  • 「ドキュメント」フォルダを開き、右クリックから「ターミナルで開く」をクリック
  • 「magick logo: logo.gif」と入力。ドキュメント・フォルダにlogo.gifというファイルができる。
  • フォルダ画面からlogo.gifをダブルクリック。ImageMagickのロゴが表示される

以上が確認できれば正常にインストールできています。

RMagickのインストール

RMagickはRubyのGem(ライブラリのこと)で、RubyImageMagickを使うためのものです。 使い方はオリジナルのImageMagickとは違い、Rubyプログラムに適した形になっています。 詳細はRMagickのドキュメントを参照してください。

ターミナルからgemコマンドでインストールします。

> gem install rmagick
Temporarily enhancing PATH for MSYS/MINGW...
Building native extensions. This could take a while...
Successfully installed rmagick-5.3.0
Parsing documentation for rmagick-5.3.0
Installing ri documentation for rmagick-5.3.0
Done installing documentation for rmagick after 2 seconds
1 gem installed
>

RMagickのテスト

エディタで次のプログラムを作成し、test.rbのファイル名で保存します。 保存先のディレクトリはどこでも良いのですが、一応ドキュメント(Documents)にしておきましょう。

require 'rmagick'
include Magick

img = Image.new(800,600) do |options|
    options.background_color = 'blue'
end
img.write("blue.png")

端末から実行します。 まず、カレント・ディレクトリがドキュメントになっていることを確認しておいてください。

> ruby test.rb
>

同じフォルダにblue.pngができているはずです。 それは800x600サイズで全面青色の画像ファイルです。 それができていれば、RMagickはきちんと動作しています。

RMagickの応用

RMagickを使ってプロジェクターの画面解像度に写真サイズを合わせるプログラムが、 「プロジェクター用スライドの画像について」にありますので、参考にしてください。

この他にもいろいろなことができるので、RMagickのドキュメントを参考に試してみると良いと思います。

WindowsにRubyをインストール

関係者との互換性のため、Windowsでの作業が増えてきました。 しかし、WindowsLinuxと比べツールが少なく、使い勝手がよくありません。 それを解消するための手段のひとつとして、Rubyをインストールすることにしました。

Rubyのウェブサイトからダウンロード

  • Rubyのウェブサイトをブラウザで開き、「ダウンロード」ボタンをクリック
  • Rubyのインストール方法」を見ると「Windowsマシンでは、RubyInstallerといったツールが使えます。」とある
  • その文の中にある「RubyInstaller」をクリック
  • 「RubyInstaller」という別サイトが開く
  • 「Download」ボタンをクリック
  • Ruby+Devkit 3.2.2-1 (x64)」をクリック=>ダウンロード開始(バージョンは2023/8/26時点)
  • ダウンロードしたインストーラをダブルクリック。以下指示に従いインストールする

エディタのダウンロード

Rubyプログラムを書くためのエディタをインストールします。 私は、Visual Studio Codeをインストールすることにしました。 もちろん他のエディタ、例えばAtomなどでも良いと思います。

  • Visual Studio Codeのウェブサイトをブラウザで開く
  • Visual Studio Codeをダウンロードする」ボタンをクリック
  • Windows」のボタンをクリック。別画面に遷移すると同時にダウンロードも行われる
  • インストーラをダブルクリックして起動。以下指示に従う。私は「デスクトップにアイコンを作成」にもチェックを入れた

テスト

アプリケーションが動くかどうかテストします。 エディタを立ち上げ、次のプログラム「hello.rb」を作り、保存します。

print "Hello world.\n"

そのフォルダで右クリックし「ターミナルで開く」をクリック。 ターミナルが開き、そのカレント・フォルダがプログラムのあるフォルダになっています。 次のようにコマンドから入力します。 なお、プロンプトは、フォルダのパス名に「>」がついたものになりますが、以下では単に「>」のみとします。

> ruby hello.rb
Hello world.
>

Hello world.が表示されればRubyは動作しています。

Rubyチュートリアル

Rubyの使い方については徒然なるままにRubyというチュートリアルを書いていますので参考にしてください。

BOMについて

WindowsRubyプログラムを作るときに問題となるBOMについて書いておきます。 BOMは「Byte Order Mark」、すなわちバイト順を表すマークでファイルの先頭にあります。 このマークはバイト順だけでなく、Unicodeのどれを使うかも示しています。 「バイトオーダーマークの使用」を参考にしてください。

例えば端末から

> echo abc >test.rb
>

とすると、ファイルの先頭に十進で「254, 255」というデータが入ります。 十六進では「FE, FF」です。 これが表すのは、UTF-16でビッグエンディアンの形式でデータが表されるということです。 RubyはBOM無しのUTF-8をプログラムのエンコーディングとしているので、test.rbを実行するとエラーになります。

以上から、Rubyのプログラムを作るときにはBOM無しのUTF-8を出力するようエディタを設定しておいてください。 VSCodeはデフォルトでそのようになっています。 ただし、BOM付きのファイルを読み込んで編集する場合は、上書き保存も同じBOMつきになります。 ですから、最初からVSCodeでファイルを作成することをお勧めします。

このエラーは見た目には良く分からないので、対策を立てにくいものです。

WindowsにGimpをインストール

最近どうしてもWindowsを使わなければならない事情が発生しました。 普段使っていないので、アプリの数も少なく、不自由しています。 Windowsを使わなければならない理由は、やりとりする相手との互換性から、Officeでファイルを作成しなければならないことです。 今のところ、Word、ExcelPowerPointの3つです。 パワポは画像を使うことも多いので、画像処理のソフトが必要になりました。 いろいろ調べてみましたが、フリーなものではGimpがまだ有力なようです。 ベストではないと思いますが、自分の仕事の範囲では十分そうです。

Gimpのインストール

インストールは簡単です。

GimpはまだGTK4対応ではないようです。 つまりGTK3使用です。 早くそのへんが改善されると良いのですが。

Gimpの初歩の初歩

Gimpの使い始めはどうやって線を引くのかがわかりにくいと思います。

  • 長方形を描くには、長方形の選択をして、メニューから「編集」=>「選択範囲の境界線を描画」をクリック
  • 円や楕円も選択範囲を「楕円選択」にして、同様にすれば描ける。
  • 複雑な曲線はパスを利用する。パスを引いておいて、メニューから「編集」=>「パスの境界線を描画」をクリック

ドキュメントもあるので、コツコツ続けていけば、そのうち慣れてきます。 がんばりましょう。

今後は・・・

今後の環境整備はRubyImagemagickおよびRMagickのインストールです。 ここまでで、画像関係は何とかなるでしょう。 この話題は次回の記事で扱おうと思います。