このエントリーをはてなブックマークに追加
2014/8/10

小数(浮動小数点数)から分数へ近似的に変換する

小数(浮動小数点数)を、適当な誤差の範囲内で、近い分数に変換するプログラムです。

RINEARN CODE - 小数(浮動小数点数)から分数へ近似的に変換する
スクリーンショット
※ ダウンロードしたZIPファイルを展開し、中のVCSSL.jarをダブルクリックして下さい。
※ 各種デスクトップOSで動作しますが、動作には Java が必要です。

概要

このプログラムは、小数を、適当な誤差の範囲内で、近い分数に変換するプログラムです。なお、ここでの小数とは、関数電卓や計算機などでよく使われる形式の、いわゆる浮動小数点数を指します。

使用方法

このプログラムは、Webページ上でも、ダウンロードしてでも使用できます。

Webページ上で起動

上の画面の実行ボタンを押すと、実行用のWebページに移動し、プログラムが起動します。うまく動かない場合はこちらのJavaScript版もあります。

ダウンロードして起動

上の画面のダウンロードボタンを押して ZIP ファイルをダウンロードし、 解凍した中にある「 VCSSL.jar 」をダブルクリックすると、プログラムが起動します。 なお、ZIPファイルの解凍は、右クリックして「 すべて展開 」などで行えます。

起動後の操作方法

起動すると、まず変換したい値を尋ねられます。ここで分数に変換したい小数の値を入力してください。Ctrlキー と V キーの同時押しで、貼り付けができます。 たとえば、21.333333333333 などを入力してみてください( 64/3 の値です )。

小数入力画面

続いて、分母の上限を尋ねられます。変換結果は、ここで指定した範囲から、変換対象の小数値に近い分数の値を片っ端から求めて、比較する事によって探されます。 普通は 10000 程度でいいと思います。あまり広い範囲から探して、123456789/1000000000 のような強引な結果が得られても微妙なので…

探索範囲入力画面

最後に、入力された小数と、結果の分数との間に、許容できる誤差の範囲を尋ねられます。指定した誤差の範囲内に収まる分数が、変換結果として表示されます。

誤差範囲画面

入力が終わると、分数の探索が始まり、結果が表示されます。この場合の例では 64 / 3 が得られます。

結果出力画面

なお同時に、その分数を浮動小数点数で実際に近似した値も表示されます(上図参照)。 あくまで近似的な浮動小数点数であるため、末尾に丸め誤差や桁落ち誤差を含む場合がありますが、妥当性判断の参考にしてください。

背景や処理内容など

小数を分数に直したい…

例えば、表計算ソフトのセルとか、数値計算のパラメータとかに、パッと見た感じではでたらめな小数が突然書いてあって、 「この値は確か、何かの整数同士で割り算した(分数の)値だったと思うけれど、メモっていなかったので忘れてしまった… もとの分数が何だったか知りたい ! 」 という場合、手計算でもとの分数を求めるのは結構面倒です。

個人的に、つい最近まさにそういった必要に迫られたため、自動でいい感じの分数を探してくれるよう、即席で書いたのがこのプログラムです。

処理内容

即席なので処理内容も結構単純で、「与えられた小数に近そうな分数を片っ端から探し、その値を求めて、誤差が一定範囲内であれば正解と見なして表示する」という感じの処理になっています。

本当はもうちょっと数学的にうまいことやれるのでは、と思いますが、とりあえず個人的にはもう目的を達成できたので、そのまま公開します。 もしいつか、莫大な大きさの分母・分子を持つ分数でも探す必要が生じた場合などは、また手を入れるかもしません。

「近くなりそうな分数」の範囲

上で「近くなりそうな分数を探す」と言いましたが、人間だと勘で適当にそれっぽいのを試すという事ができても、コンピュータに勘はないので、この点に少し補足を加えておきます。

一番単純な探し方として、例えば「分母と分子それぞれ 1 から 100万 まで、全ての組み合わせから探す」みたいなものが思い浮かびますが、 それだと総数は100万の2乗で1兆通りなったりして、探す範囲がやや大変な事になり、入力から出力までのレスポンスが遅れて地味に鬱陶しいです。 その1兆個の分数の中には、比べるまでもなく大きすぎたり、小さすぎたりするやつが大半で、目的の小数に近いやつはごくごく一部です。

さすがそれだと効率が悪すぎるので、少し探す範囲を絞り込みます。 分数に直したい小数の値を f としましょう。そして、ある分母の整数 i が与えられたとして、分子を探す範囲を絞り込みます。 まず、当たり前の事ですが「 f*i / i = f 」となりますね。 という事は、f*i に近い整数を分子にすれば、分数の値は f に近いはずです。

f*i の端数を切り捨てて整数にしたものを j1 としましょう。これは f*i 以下の値であるため、分数 j1 / i は f 以下の値となります。

また、整数化で切り捨てた端数は1以下なので、j1 + 1 を新たに j2 とすると、これは f*i より大きい値となり、従って分数 j2 / i は f より大きい値となります。j1の逆ですね。

j1 と j2 は隣接する整数なので、挟み撃ち的な感じで、結局はこの2つを分子として採用すれば、どちらかが最も近い分数値を与えてくれます。 つまり、ある分母 i の値について、分子は f*i と f*i+1 の2通りだけ採用すれば、近似値を探す範囲としては十分なわけです。 あとは、分母 i をひたすら増やしていって、誤差が規定範囲内に収まる分数を探せば OK です。

コード解説

実際のプログラムのコード内容について簡単に説明します。 このプログラムのコードは、Cライクな簡易プログラミング言語 VCSSL で記述されています。 今回の内容は単純なので、大体C言語っぽい感覚で読める感じになっていると思います。

なお、JavaScript版のコードもVCSSL版とほとんど同じなので、ここではとりあえずVCSSL版のコードで解説します。 JavaScript版のコードはJavaScript版のページに掲載しています。

コード全体

まずは、コード全体を見てみましょう。30行程度の短いコードです。

以上です。流れとしては、先頭あたりでユーザーから近似対象の小数値やパラメータを入力してもらい、 真ん中あたりでループを回して近い分数を探し、見つかれば出力してそのままプログラムを終了する感じです。 良い分数が見つからなければ、ループを抜けて末尾まで下りてきて「見つかりませんでした」と言って終了、といった具合です。

以下では、各部についてもう少し見てみます。

先頭部分

まず先頭部分です。

先頭の「 encode Shift_JIS; 」では、プログラムの文字コードを明示しています( UTF-8も可 )。必須ではありませんが、書いておくと文字化けするのを防げます。

「 import Math; 」の部分は、数学関数を扱うためのライブラリ「 Math 」を読み込んでいます。誤差の絶対値を求める際に abs 関数を使うので必要です。

ユーザー入力

続いて、ユーザーに近似対象の小数値やパラメータを入力してもらう部分です。

input関数は、ダイアログを表示して、ユーザーに値を入力してもらうための関数です。 input関数の戻り値は string ですが、float や int で受け取っているので、代入時に暗黙的に変換されます。

近い分数を探す

続いて中核部分です。分母 i を増やしながら、近似対象の小数 f に近い分数を探します。

処理内容の解説でも述べた通り、それぞれの分母 i について、分子は f*i と f*i+1 の2通りから探せば十分です。

誤差が規定範囲内に収まるものが見つかった場合は、出力してそのまま exit でプログラムの実行を終了します。

見つからなかった場合の処理

見つからなかった場合は、上のループを抜けて、見つからなかった旨を告げて実行終了します。

コードのライセンス

このVCSSLコードは著作権フリー(パブリックドメイン)で公開しています。JavaScript版のコードも同様です。 そのままでのご利用はもちろん、言語の種類を問わず、改造や流用などもご自由に行ってください。



スポンサーリンク


このエントリーをはてなブックマークに追加
新着プログラム

台形近似による数値積分
2015年06月25日

長方形近似による数値積分
2014年11月01日

小数(浮動小数点数)から分数へ近似的に変換する
2014年08月10日

ユーザーが入力した数式を2次元グラフにプロットする
2013年11月30日

配列を3次元グラフにプロットする
2013年11月28日

配列を2次元グラフにプロットする
2013年11月28日

ファイルを3次元グラフにプロットする
2013年11月27日

ファイルを2次元グラフにプロットする
2013年11月26日

ウィンドウの生成
2013年08月28日

ボタンが並ぶパネルの配置(ButtonPanel)
2013年08月28日

ボタンの配置
2013年08月28日

2DCGと3DCGの合成
2013年05月04日

凹レンズを通過する波のシミュレーション
2013年03月16日

凸レンズを通過する波のシミュレーション
2013年03月15日

乱雑な密度分布における波のシミュレーション
2013年03月12日

ローレンツアトラクタ(ファイル出力版)
2013年02月28日

波の屈折のシミュレーション
2012年12月05日

力学アルゴリズムによる波のシミュレーション(面上の波)
2012年11月21日

手動で波を発生させるシミュレーション
2012年11月19日

力学アルゴリズムによる波のシミュレーション(線上の波)
2012年11月18日

カラーコードとRGBの相互変換と色表示
2012年11月15日

頂点配列によるモデルの変形アニメーション
2012年11月14日

頂点配列によるモデルの作成(四角形格子メッシュ形式)
2012年11月11日

円周率1万桁の計算(ガウス=ルジャンドル法)
2012年08月22日

2DCG用フレームワークの使用サンプル(アニメーション版)
2012年08月09日
  スポンサー リンク

  おすすめ / 人気のコーナー
フリーソフト
RINEARN では、インストール不要の各種解析ソフトを無償公開しています。Windows 8.1 で動作確認済み !
ピックアップ
【VCSSL実践講座】 3Dグラフ描画ツールを作ろう!
C言語系の簡易プログラミング言語「 VCSSL 」で、色々なものを作っていく連載記事コーナーです。現在は3Dグラフ描画ツールを開発中 !
2013年08月29日
【RINEARN CODE】 凸レンズを通過する波のシミュレーション
凸レンズ形状の高密度媒質を通過する、波のシミュレーションです。まっすぐ入射した波がレンズ通過時に屈折し、焦点へ収束する様子がアニメーションで楽しめます。
2013年03月15日
  新着情報
RSSフィード
RINEARN の新着・更新情報をRSSフィードで配信しています !
新着リスト
台形近似による数値積分

積分の値を数値的に求めます。長方形近似よりも高精度な方法として、台形で近似した微小領域を足しあげる方法を使用します。
2015年06月25日
長方形近似による数値積分

積分の値を数値的に求めます。長方形で近似した微小領域を足しあげる、最も単純な方法を使用します。
2014年11月01日
小数(浮動小数点数)から分数へ近似的に変換する

小数(浮動小数点数)を、適当な誤差の範囲内で、近い分数に変換するプログラムです。
2014年08月10日
ベクターソフトニュース様でリニアングラフ3Dをご紹介頂きました!

オンラインソフトウェア流通サイトVector様の「ベクターソフトニュース」コーナーにて、リニアングラフ3Dを取り上げて頂きました。
2014年07月31日
ユーザーが入力した数式を2次元グラフにプロットする

実行時にユーザーが入力した数式の値を、2次元グラフにプロットするサンプルプログラムです。
2013年11月30日
配列を3次元グラフにプロットする

座標値配列の内容を、3次元グラフにプロットするサンプルプログラムです。
2013年11月28日
配列を2次元グラフにプロットする

座標値配列の内容を、2次元グラフにプロットするサンプルプログラムです。
2013年11月28日
ファイルを3次元グラフにプロットする

座標値ファイルの内容を、3次元グラフにプロットするサンプルプログラムです。
2013年11月27日
ファイルを2次元グラフにプロットする

座標値ファイルの内容を、2次元グラフにプロットするサンプルプログラムです。
2013年11月26日
2013年の不具合修正情報

2013年1月〜12月に実施された不具合修正に関する情報を掲載しています。
2013年11月01日
3Dグラフ描画ツールを作ろう!〜第5回縮尺を自動調整する

VCSSL実践講座、3Dグラフ開発編。第5回では、最大最小値に応じて、縮尺を自動調整する処理を実装します。
2013年09月02日
3Dグラフ描画ツールを作ろう!〜第5回縮尺を自動調整する

VCSSL実践講座、3Dグラフ開発編。第5回では、最大最小値に応じて、縮尺を自動調整する処理を実装します。
2013年09月02日
  Twitter