Hatena::ブログ(Diary)

エンジニアのソフトウェア的愛情 このページをアンテナに追加 RSSフィード Twitter

2016-09-20

Fiddle を掻き鳴らしてみる

*.dllや*.soなど、ダイナミックリンクライブラリを扱うためのライブラリです。

Ruby は痒い所に手が届く便利な言語だと知ってはいましたが、こんなに便利になっているとは思いませんでした。

と、いうわけで。


Fibonacci Number

まず。適当な .so ファイルを用意します。

// libfib.cpp

#include <map>

namespace
{

std::map<int, int> memo;

}

extern "C"
{

int fibonacci_number(int n)
{
    if(n < 1)
    {
        return 0;
    }
    else if(n <= 2)
    {
        return 1;
    }
    else
    {
        if(memo.find(n) == memo.end())
        {
            memo[n] = fibonacci_number(n - 1) + fibonacci_number(n - 2);
        }
        return memo[n];
    }
}

}

.so ファイルの生成。オプションは環境に合わせて指定してください。私は El Capitan 。

$ g++ --std=c++11 -dynamiclib -o libfib.so libfib.cpp

次に。ライブラリを呼び出すモジュールを作成。extern に続いて文字列で C 言語の関数の定義をそのまま書けば済んでしまうとか、予想外の簡単さ。

# fibonacci.rb

require 'fiddle/import'

module Fibonacci
  extend Fiddle::Importer
  dlload './libfib.so'

  extern 'int fibonacci_number(int n)'
end

サンプル用意。

# sample.rb

require './fibonacci'

puts Fibonacci.fibonacci_number(10)
puts Fibonacci.fibonacci_number(20)
puts Fibonacci.fibonacci_number(30)
puts Fibonacci.fibonacci_number(40)

実行。

$ ruby sample.rb 
55
6765
832040
102334155

簡単すぎる。


Fibonacci Series

配列を扱うときは Array#pack, Array#unpack を使って文字列(バイト列)を経由して扱う模様。

配列を扱う関数を追加。

// $ g++ --std=c++11 -dynamiclib -o libfib.so libfib.cpp

#include <map>

namespace
{

std::map<int, int> memo;

}

extern "C"
{

int fibonacci_number(int n)
{
    // 省略
}

void fibonacci_series(int n, int* s)
{
    for(int i = 1; i <= n; ++i)
    {
        s[i - 1] = fibonacci_number(i);
    }
}

}

同じ要領で .so ファイルを作成。

定義を追加。

# fibonacci.rb

require 'fiddle/import'

module Fibonacci
  extend Fiddle::Importer
  dlload './libfib.so'

  extern 'int fibonacci_number(int n)'
  extern 'void fibonacci_series(int n, int* s)'
end

呼び出し。

# sample2.rb

require './fibonacci'

s = [0].pack('i') * 10            # int 型のサイズのバイト列を 10 並べたものを用意
Fibonacci.fibonacci_series(10, s) # 関数呼び出し
puts s.unpack('i' * 10)           # int 型の値 10 個に戻す

実行。

$ ruby sample2.rb 
1
1
2
3
5
8
13
21
34
55

簡単すぎる。


いつか聴くはずっと聴かない:古楽器楽団「タブラトゥーラ」

フィドルといえば、思い出すのはタブラトゥーラ。

http://www.dowland.jp/tablatura/phot2/tab.jpg

ダウランドアンドカンパニイ 公式サイトより)


これがフィドル。

http://www.dowland.jp/tablatura/phot2/tasaki.jpg

同サイトより)


CD 購入は こちら から。サンプルも聴けます。

2016-08-21

Retriable gem の使い方のめも

インストール

$ gem install retriable

実装例

require 'retriable'

class SampleError < RuntimeError
end

puts <<~EOS
  | exception       | try | elapsed_time | time         |
  |-----------------|-----|--------------|--------------|
EOS

Retriable.configure do |c|
  c.tries = 5
  c.base_interval = 1
  c.rand_factor = 0
  c.on = SampleError
  c.on_retry = -> (exception, try, elapsed_time, next_interval) {
    puts format('| %-15s | %3d | %12f | %-12s |', exception, try, elapsed_time, Time.now.strftime('%H:%M:%S.%L'))
  }
end

begin
  Retriable.retriable do |try|
    raise SampleError if try < 5
  end
  puts format('| %-15s | --- | ------------ | %-12s |', 'done', Time.now.strftime('%H:%M:%S.%L'))
rescue SampleError => e
  puts format('| %-15s | --- | ------------ | %-12s |', e, Time.now.strftime('%H:%M:%S.%L'))
end

実行。

$ ruby samle.rb
| exception       | try | elapsed_time | time         |
|-----------------|-----|--------------|--------------|
| SampleError     |   1 |     0.000040 | 13:29:53.806 |
| SampleError     |   2 |     1.005182 | 13:29:54.811 |
| SampleError     |   3 |     2.508871 | 13:29:56.315 |
| SampleError     |   4 |     4.764138 | 13:29:58.570 |
| done            | --- | ------------ | 13:30:01.948 |

リトライ回数を 3 回にしてみます。

# 略

Retriable.configure do |c|
  c.tries = 3
  # 略
end

# 略

実行。

$ ruby sample.rb 
| exception       | try | elapsed_time | time         |
|-----------------|-----|--------------|--------------|
| SampleError     |   1 |     0.000041 | 13:35:22.001 |
| SampleError     |   2 |     1.000827 | 13:35:23.002 |
| SampleError     |   3 |     2.501092 | 13:35:24.502 |
| SampleError     | --- | ------------ | 13:35:24.502 |

2016-07-01

抵抗器のカラーコードは虹の色

会社で「抵抗器のカラーコードは虹の順番だよ」という話をしたら。

「いや、そもそも虹の色の順番覚えてないから」と返されてしまいました。


そんなわけなので、Rubygem にしてみました。

gem は書き慣れていないので、雑です。


虹の色

「せき とう おう りょく せい らん し」と覚えます。「赤 橙 黄 緑 青 藍 紫」。

ただしカラーコードには「藍」は使われず「赤 橙 黄 緑 青 紫」の 6 つを使います。

前に「黒 茶」、後ろに「灰 白」を加えた「黒 茶 赤 橙 黄 緑 青 紫 灰 白」を 0 から 9 に割り当てます。


gem にしてみた

まず。Gemfile を書きます。

source "https://rubygems.org"

gem 'color_code', github: 'mattsan/color_code'

インストールします。

$ bundle install

irb で動作確認。

color_code_sample $ bundle exec irb
irb(main):001:0> require 'color_code'
=> true
irb(main):002:0> resister = '青緑赤金'.to_resister
=> 65 * 10**2 ± 5.0%
irb(main):003:0> resister.to_f
=> 6500.0
irb(main):004:0> resister.significant_digits
=> 65
irb(main):005:0> resister.multiplier
=> 2
irb(main):006:0> resister.tolerance
=> 0.05
irb(main):007:0> resister.lower_bound
=> 6175.0
irb(main):008:0> resister.upper_bound
=> 6825.0

誤差の範囲の上限下限も計算します。


いつか読むはずっと読まない:半世紀前の作品

原著 “ Way Station” が著されたのが 1963 年。サイエンス・フィクションというカテゴリにあると、科学や技術の発展に伴って陳腐化するのではないか、古くさくなるのではないか、という感覚を抱いてしまいますが。物語の面白さはそんなこととは無縁でした。


2016-06-29

どう書くのたのしみ

横浜へなちょこプログラミング勉強会 オフラインリアルタイムどう書く神田に移ってきてやがて半年になります。

場所が住んでいるところから近くに移ったということもあって、ようやくオフラインで参加できるようになりました。

ふりかえってみるとオンラインながら どう書く のコードを書き始めたのが4年前。

気がつくと長いおつきあいになっていました。

ようやくオフラインで参加できるようになって、感じたことを少し。

当日

頭が真っ白になる、あの感じ

制限時間内にコードを書き上げなければならないのに、問題を見た瞬間に一行も書けないんじゃないか、という気がするあの感じ。

学生の頃はよく経験したこの感覚ですが(ォィ)、それが懐かしくもあり新鮮でもあり。

その状態から解法を閃いて書ける! と感じた時のあの安堵感もなんとも言えません。


脇目も振らずコードを書く、あの感じ

仕事で書くコードは、慎重に書くようにしています。何かと早とちりする性格なので、小さく手を進めるようにしています。

そいうのをかなぐり捨てて、閃いた解法をコードに変換する行為に没頭する、あの感じ。

入力データがどのように流れて出力データになるのか見えていて、途中の動作確認もそこそこにコードを書く。コードの最終形態に頭から突っ込む。

…そしてだいたいはテストが通らず焦りながらデバッグする後半になるのですが、それはまた別のお話。


他の参加者のアイディアを知る、書き方を知る

当日参加された方の多くは、書いたコードをネット上に公開してくださっていますが、そこに至った経緯の解説はどうしても少なくなります。また解けたアイディアの解説はあっても、失敗したアイディアや、つまずいたところは、あまり表に出てきません。

当日は、その人が、その場所で、その問題を考えた、生のアイディアを伺う機会がえられます。勘違いだったり、遠回りだったり、明後日の方向を向いていたりすることもありますが、それを思いついた背景を聴ける機会はとても貴重。

加えてコーディング技法もいろいろと知ることができます。


飲む

コードを書いて、互いにコードを読んで、そのあとは懇親会です。


…。

そんなことも、あります。


後日

深く深く考える

気になる問題に遭遇すると、何日も考える癖があります。二日も三日も考え続けると、ふと新しいアイディアが降りてくる瞬間があります。

そんなアイディアが降りてきたときは、言葉で定義し文章に書き出すことをしています。そうすると一段高いところから問題が見えるようになった気がします。


こうすることでコードを書くときの視野が高く遠く広くなってゆく感じがしています。


次回

そして次回は。今週末の開催です。


いつか読むはずっと読まない:ハッカーのたのしみ

すでに何回も紹介していますが。良書です。現在入手は困難なようですが、見つけたらぜひ手にとって読んでみてください。


2016-05-28

Ruby/RSVG と Cairo を使って SVG から PDF を生成しためも

前回C++ で書いたのですが、調べたら Ruby でも同じように書くことができることがわかりました。

今回は libRSVG を Ruby から利用する Ruby/RSVG (rsvg2 gem) を利用。


require 'rsvg2'

source = <<~EOS
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg
   xmlns='http://www.w3.org/2000/svg'
   version='1.1'
   width='210mm'
   height='297mm'
>
  <rect x='100' y='100' width='100' height='100' fill='red' />
  <text
    font-family='sans-serif'
    font-size='18'
    x='200'
    y='200'>エンジニアのソフトウェア的愛情</text>
  <text
    font-size='12'
    x='200'
    y='220'>または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか</text>
</svg>
EOS

svg = RSVG::Handle.new_from_data(source)

dim = svg.dimensions

puts "document size = #{dim.width}x#{dim.height}"

surface = Cairo::PDFSurface.new('sample.pdf', dim.width, dim.height)

cairo = Cairo::Context.new(surface)

cairo.render_rsvg_handle(svg)

結果は前回と同じです。

Cairo::PDFSurface.new の第一引数文字列を渡すと出力先のファイルのファイル名と解釈します。第一引数write メソッドを持つオブジェクトを渡すと、そのメソッドを使って結果を書き出します。

詳しくはこちら: http://cairo.rubyforge.org/doc/ja/cairo-pdf-surface.html



SVG をベタに書くのがになったので、 Haml で描き直してみました。

ついでに Cairo::PDFSurface.new の第一引数Fileインスタンスwrite メソッドを持つオブジェクト)を渡しています。

HamlSVG を書く話は 以前の記事 なんかもご参照ください。

require 'haml'
require 'rsvg2'

source = Haml::Engine.new(<<EOS).to_html
!!! XML
%svg{xmlns: 'http://www.w3.org/2000/svg', version: '1.1', width: '210mm', height: '297mm'}
  %rect{x: 100, y: 100, width: 100, height: 100, fill: 'red'}
  %text{font: {family: 'sans-serif', size: 18}, x: 200, y: 200} エンジニアのソフトウェア的愛情
  %text{font: {size: 12}, x: 200, y: 220} または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか
EOS

svg = RSVG::Handle.new_from_data(source)

dim = svg.dimensions

puts "document size = #{dim.width}x#{dim.height}"

surface = Cairo::PDFSurface.new(File.new('sample.pdf', 'w'), dim.width, dim.height)

cairo = Cairo::Context.new(surface)

cairo.render_rsvg_handle(svg)


いつか読むはずっと読まない:バチガルピ短篇

イーガンをまとめて読んでいた時期があったせいか、第一篇を読んでてイーガンを読んでいるような錯覚をしてしまいました。設定が。

作風が似ているかどうか判断できるほど、わたしの SF 脳は肥えていない。