浮動小数点数と数値計算

7月 15th, 2008 admin

あいかわらず「アルゴリズムとデータ構造シリーズ」です。今回は第8章「浮動小数点数と数値計算」です。

浮動小数点数

float型やdouble型の数値はコンピュータの内部では
符号と指数(n)と基数(a)で表現されている。
たとえば12.8なら
基数=0.8
指数=4

0.8*2^4
という具合です。なのでその表現の都合で、あまりにも大きかったり小さかったりする数字は正確には表せないということがあるというお話

数値計算

簡単な数値計算の例として5次方程式を解くというもののコードを書きました。
バイナリサーチを用いて、答えのある範囲をだんだんと絞っていくものです。

RUBY:
  1. #func
  2.  
  3. def func(x)
  4.     x = (x * x * x * x * x) - (10.0 * x * x * x * x) + (25.0 * x * x * x) + ( 40.0 * x * x) + ( 200.0 * x) - 500.0
  5.     return x
  6. end
  7.  
  8.  
  9. def binary_search
  10.   epsilon = 0.00001
  11.   left = 1.0
  12.   right = 3.0
  13.  
  14.   while((right-left).abs> epsilon && func(left).abs> epsilon)
  15.     mid = (left+right)/2.0
  16.     if(func(left)*func(mid)>=0.0)
  17.       left=mid
  18.     else
  19.       right=mid
  20.     end
  21.   end
  22.  
  23.   return left
  24. end
  25.  
  26. d = binary_search
  27. p d
  28. printf("answer is %1f. and func(x) is %1f \n",d,func(d))

まとめ

コンピューターなのに不正確な答えを出すと言うのがなんだか面白いですね。

※このシリーズは私がRubyでアルゴリズムとデータ構造を基礎から学ぶ記録です。全体の目次はこちらへ。

パトランプでサーバ監視 with Gainer,Ruby

7月 14th, 2008 admin

CSNagoyaのLTで「RubyとGainerで行うサーバ監視」というタイトルで発表しました。

概要

サーバがピンチだっていうのにアラートメールが届くだけなんて地味すぎだろ
というコンセプトのもとに、サーバのロードアベレージをチェックし、高いようであればパトランプを点灯させるというものを作ってみました。本来のサーバ監視という意味ではロードアベレージだけチェックするのはいまいちですが、そのあたりは改良していきたいと思います。むしろRubyとGainerだけで、こんなに簡単にできるんだということが伝われば幸いです。

動作している様子

といっても、パトランプが点灯するだけですが。仕事中に突然これが光りだすのはエキサイティングです。

システム概要

all.png
非常に単純ですね。調査もとのマシンから、監視対象サーバにSSHでログインしてロードアベレージをチェックします。その後ロードアベレージが一定の値を超えていたらGainer経由でパトランプを点灯させます。

回路

dsc00243.jpg
パトランプは12Vで動くものです。ネタのためだけに欲しかっただけなのに6000円もして悲しかった。
gainer_map.gif
回路図はこんな感じです。Gainerから出る信号は弱い(多分3Vぐらい?)なので当然パトランプを直接点灯させられません。そこでパトランプにはリレーと12Vの電源をつけてやり、そのリレーのON/OFFをトランジスタによるスイッチで行いました。

コード

たったこれだけのコードでできるというのが驚きです。Gainerとのやり取りはFunnelというソフトを使いました。GainerやArduinoに対応した便利なツールキットのことでIOのフィルタなどをいい感じにやってくれるものです。

RUBY:
  1. require 'rubygems'
  2. require 'net/ssh'
  3. require 'funnel'
  4.  
  5. def get_load_average(str)
  6.   return str.slice(/load average: ([^,]+)/,1).to_f
  7. end
  8.      
  9. module Funnel
  10.     la = 0.0
  11.     Net::SSH.start(ARGV[0], ARGV[1], :password => ARGV[2]) do |ssh|
  12.       la = get_load_average(ssh.exec!('uptime'))
  13.     end
  14.    
  15.     if la> 2
  16.       gio = Gainer.new(Gainer::MODE1)
  17.       gio.aout(0).value = 1
  18.       sleep(300)
  19.     end
  20. end

発表資料

まとめ

今回はGainerとRubyでパトランプを点灯させてみました。Gainerについて興味をもったかたは以前エントリーを書きましたのでそちらをご覧下さい。

また8月に開催されるOSC NAGOYAには開発者の小林茂さんが講演に来てくださいます。
お近くのかたは是非ご参加ください。

マップとハッシュ(ハッシュマップ)

7月 13th, 2008 admin

今回は「アルゴリズムとデータ構造シリーズ」です。前回に続いて第7章「マップとハッシュ」のハッシュマップの実装について。

ハッシュ値が重複した場合の対策

ハッシュ値が重複した場合には「k^2番目に再ハッシュする」という方法で対応した。
たとえばハッシュ値が2だった場合には
・3(2+1*1)
・6(2+2*2)
・11(2+3*3)
と試していく方法だ。

コード

検索と削除の部分は少しずるをしました。

RUBY:
  1. #Hash Map
  2. $KCODE = "SJIS"
  3.  
  4. class WordSet
  5.   attr_accessor :english, :japanese
  6.   def initialize(english = nil, japanese = nil)
  7.     @english = english
  8.     @japanese = japanese
  9.   end
  10. end
  11.  
  12. class HashMap
  13.   def initialize(size)
  14.     @hash_table_size = size
  15.     @hash_table = Array.new
  16.   end
  17.  
  18.   def make_hash(str)
  19.     weight = 0
  20.     hash = 0
  21.     str.each_byte{|s|
  22.       weight = 0 if weight> 7
  23.       hash += s * (256 ** weight)
  24.       weight+=1
  25.     }
  26.     hash % @hash_table_size
  27.   end
  28.  
  29.   def add_data(ws)
  30.     hash_val = self.make_hash(ws.english)
  31.  
  32.     unless @hash_table[hash_val].nil?
  33.       hash_val = self.rehash(hash_val)
  34.       if(hash_val == -1)
  35.         printf("%sをマップに挿入しようとしましたが、空き位置がありませんでした",ws.english)
  36.         return
  37.       end 
  38.     end
  39.    
  40.     @hash_table[hash_val] = ws
  41.   end
  42.  
  43.   def rehash(first_hash_val)
  44.     #k^2に再ハッシュする
  45.     (1...(@hash_table_size/2)).each do |k|
  46.       hash_val = (first_hash_val+k*k) % @hash_table_size
  47.       return hash_val if @hash_table[hash_val].nil?
  48.     end
  49.     return -1
  50.   end
  51.  
  52.   def find(str)
  53.     hash_val = self.make_hash(str)
  54.     return @hash_table[hash_val]
  55.   end
  56.  
  57.   def delete(str)
  58.     hash_val = self.make_hash(str)
  59.     @hash_table[hash_val] = nil
  60.     return true
  61.   end
  62.  
  63.   def print_all_data
  64.     @hash_table.each do |val|
  65.       printf("%s\t\t%s\n",val.english,val.japanese) unless val.nil?
  66.     end
  67.   end
  68. end
  69.  
  70. init_data = [
  71.                   WordSet.new("lisp","リスプ"),
  72.                   WordSet.new("C","シー"),
  73.                   WordSet.new("ruby","ルビー"),
  74.                   WordSet.new("perl","パール"),
  75.                   WordSet.new("python","パイソン"),
  76.                   WordSet.new("PHP","ピーエイチピー"),
  77.                   WordSet.new("JavaScript","ジャバスクリプト")
  78.                 ]
  79.                
  80. hash_map = HashMap.new(503)
  81.  
  82. init_data.each do |ws|
  83.   hash_map.add_data(ws)
  84. end
  85.  
  86. i = nil
  87. loop do 
  88.   print "コマンドを入力して下さい\n1:表\ 2:検索 3:削除\n"
  89.   i = gets.chomp.to_i
  90.  
  91.   case i
  92.     when 1
  93.       hash_map.print_all_data
  94.     when 2
  95.       print "検索する文字列を入力してください:"
  96.       j = gets.chomp
  97.       if ws = hash_map.find(j)
  98.         printf("%sは日本語で「%s」です。 \n\n",ws.english,ws.japanese)
  99.       else
  100.         print("見つかりませんでした。\n\n")
  101.       end
  102.     when 3
  103.       print "削除する文字列を入力してください:"
  104.       j = gets.chomp
  105.       if hash_map.delete(j)
  106.         printf("削除しました。 \n\n")
  107.       else
  108.         print("見つかりませんでした。\n\n")
  109.       end   
  110.   end
  111. end

まとめ

ハッシュというものがどういうものか(そもそもなんでハッシュと呼ばれているのか)わかって非常にすっきりできた。

※このシリーズは私がRubyでアルゴリズムとデータ構造を基礎から学ぶ記録です。全体の目次はこちらへ。

WCAN 2008 SUMMERに行きます

7月 11th, 2008 admin


wcan2008summer

明日はWCAN 2008 SUMMERに参加させていただきます。
会場でおあいしましょう!

GainerでマルチカラーLED点灯の実習

7月 11th, 2008 admin

まだまだGainerで遊んでいます。コードを書いていてRubyの資産がすべて使えるというのは本当に凄いことなんだなと思いました。今週の日曜日にCSNagoyaのHaskell勉強会にてLTの時間があるので、いまからそれなりに実用的なものをつくって発表しようと思います。

作ったもの

LEDが「青」=>「黄色点滅」=>「赤」と信号のように光ります。いかにも電子工作やプログラミングの入門っぽくていいですね。

コード

RUBY:
  1. require 'funnel'
  2.      
  3. module Funnel
  4.     gio = Gainer.new(Gainer::MODE1)
  5.     gio.aout(1).value = 1
  6.     sleep(3)
  7.     gio.aout(1).value = 0
  8.     7.times{
  9.       gio.aout(0).value = 1
  10.       gio.aout(3).value = 1
  11.       sleep(0.5)
  12.       gio.aout(0).value = 0
  13.       gio.aout(3).value = 0
  14.       sleep(0.5)
  15.     }
  16.     gio.aout(0).value = 0
  17.     gio.aout(3).value = 1
  18.     sleep(5)
  19.  
  20. end

まとめ

ちょっと大須いってくる