背景・動機など
ここ最近 こちらのQiita記事 を参考にしつつ FPGA に16ビット固定小数演算器を実装しようと日々奮闘しておりまして、FPGA やってるとビット単位で信号を扱うことになるので、当然2進数表記が重要になってきます。
Verilog のシミュレーションを Verilator の生成コードを利用しつつ、Ruby から使えるようにした話 は先日公開させていただきました。
固定にしろ浮動にしろ、何ビットで計算するにしろ、小数点つきの数を2進リテラルを Ruby でうまく表現できないものかなー、と思っておりました。ちなみに 0b010111.101
みたいな表記だと Syntax Error になります。うむむ。
小数表記をメタプログラミングで
で、1日後、「あ、method_missing
使って 0b011.b101
って書けるようにすればいいんじゃね?」と思いつきました。メタプログラミングの一種ですね。Ruby の文法上、数字で始まるメソッドは定義できませんから、一文字以上のアルファベットはどうしても必要になります。
例えば、こんなふうに書けます。
> 0b01.b01 # => (5/4)
> -0b01.b01 # => (-5/4)
ご覧の通り、内部では Rational として扱っています。私の目的にはあまり必要ではありませんが、任意精度の計算にも対応したかったので。
2進小数表記「へ」の変換
2進固定小数の表記はこれでいいとして、任意の数を2進固定小数表記「に」変換するのはどうするか。10進→2進変換はぐぐれば山と出てきますが、いずれも正の整数が前提。。。orz
でまあ数日悩んでおったのですが、なんとか形になりました。整数部と小数部の桁数を分けて書く [Q format] (https://en.wikipedia.org/wiki/Q_(number_format))というのを使います。
> 1.25.q(4,4, true) # => "0001.0100"
> -1.25.q(4,4, true) # => "1110.1100"
q
メソッドに渡す引数は順に
- 整数部の桁数
- 小数部の桁数
- 小数点を表示するか否かのフラグ。デフォルトは false 。
です。有理数にも適用できます。
> (11/8r).q(4,4,true) # => "0001.0110"
> (-11/8r).q(4,4,true) # => "1110.1010"
入手は gist で
今回は gist にあげてみました。 今回もRuby スクリプト1個なので、コードコピペしてもいいですし、git clone するなら
$ git clone https://gist.github.com/sin00b/c3cd8688294d9b41b0e1f98cce391375 hoge
としていただければいいです。
コードみていただければわかりますが、負数表記に変換するのに String#tr で置換しています。理屈としてはこれでもできるけど、ちょっとなぁって思ってます。