はてなのキーワードのバグ?
はてなダイアリープラスを使って、このブログ以外にもう1個ブログを書いています。
そこで、あるキーワードが、はてなのキーワードのページで、言及されているページの一覧から一見するとたどれるようになっているのですが、それが、このブログを指示しています。
副ブログは、はてなIDの後ろに+hogeという感じのものをつくのだが、どうも、+よりも後ろの部分が欠落しているようだ。
というわけで、はてなideaに登録しておきました。idea:27544
使い方がよくわからない。。。。。
Pythonでベイジアンフィルターを実装してみた
Web+DB Vol56でPerlでかかれていた、ベイジアンフィルターをPythonで実装してみました。
ほぼ、本に忠実に実装しています。
恒例によって、結果の保存とかはしてません。
#!/usr/bin/env python # -*- coding: utf-8 -*- import MeCab import math class Bayesian(object): term_count = {} cat_count = {} def __init__(self): pass def MecabSpliter(self, text): m = MeCab.Tagger("-Ochasen") n = m.parseToNode(text.encode('utf-8')) words = {} while n.next is not None: if n.posid == 1 or n.posid == 2 or n.posid == 3 or n.posid == 4 or n .posid == 5: words.setdefault(n.surface.lower(), 0) words[n.surface.lower()] += 1 n = n.next return words def text2vec(self, text, spliter=None): if spliter is None: return self.MecabSpliter(text) else: return spliter(text) def train(self, wv, cat): for term, cnt in wv.iteritems(): print term, cnt if not self.term_count.has_key(term): self.term_count[term] = {} if term in self.term_count[term]: self.term_count[term][cat] += cnt else: self.term_count[term][cat] = cnt if term in self.cat_count: self.cat_count[cat] += 1 else: self.cat_count[cat] = 1 def catProb(self, cat): total = 0 for k in self.cat_count: total += self.cat_count[k] return 1.0 * self.cat_count[cat] / total def termCnt(self, term, cat): if term in self.term_count: if cat in self.term_count[term]: return self.term_count[term][cat] else: return 0 else: return 0 def termProb(self, term, cat): return self.termCnt(term, cat) / self.cat_count[cat] def predict(self, vec): scores = {} for cat in self.cat_count: scores[cat] = self.score(vec, cat) return scores def score(self, vec, cat): print "tt", self.catProb(cat) cat_prob = math.log(self.catProb(cat) * 1.0) not_likely = 1.0 / (self.total_term_count() * 10) doc_prob = 0 for term, count in vec.items(): print term, count doc_prob += math.log(self.termProb(term, cat) or not_likely) * count return cat_prob + doc_prob def total_term_count(self): cnt = 0 for k in self.cat_count: cnt += self.cat_count[k] return cnt if __name__ == '__main__': filter = Bayesian() words = filter.text2vec(u'PerlやPythonはスクリプト言語です', filter.MecabSpl iter) filter.train(words, "it") words = filter.text2vec(u'Perlでベイジアンフィルタを作りました。') filter.train(words, "it") words = filter.text2vec(u'pythonはニシキヘビ科の総称です。') filter.train(words, "science") words = filter.text2vec(u'Perlは楽しい') porb = filter.predict(words) print porb words = filter.text2vec(u'PythonとPerl') porb = filter.predict(words) print porb words = filter.text2vec(u'pythonはヘビ') porb = filter.predict(words) print porb
あと、雑誌に書いてあるとおりに設定されたMeCabが必要です。
apt-getで入れたものを使う場合、多少変更が必要です。
- 作者: 赤松祐希,紀平拓男,牧大輔,西林孝,中島聡,中島拓,角田直行,はまちや2,舘野祐一,きしだなおき,和田裕介,伊藤直也,大沢和宏,塙与志夫,増井俊之,ミック,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2010/04/24
- メディア: 大型本
- 購入: 14人 クリック: 180回
- この商品を含むブログ (40件) を見る
32bit Protect Mode
ようやく完全に32bitに移行できたので、その記録。
まずは、IPL。
.code16gcc _start: JMP entry // for FAT12 .byte 0x90 .ascii "HelloIpl" .word 512 .byte 1 .word 1 .byte 2 .word 224 .word 2880 .byte 0xf0 .word 9 .word 18 .word 2 .int 0 .int 2880 .byte 0,0,0x29 .int 0xffffffff .ascii "HELLO-OS " .ascii "FAT12 " .skip 18,0 entry: // レジスタの初期化 movw $0x0, %ax movw %ax, %ss movw %ax, %dx movw %ax, %ds movw %ax, %es // 0x7c00に読み込まれるので、SPを0x7c00にしないとアドレスの // 設定が煩雑になるため。 movw $0x7c00, %sp // フロッピーディスクを読み込む // 読み込む先を設定する。 movw $0x0820, %ax movw %ax, %es // シリンダ0 ヘッド0 セクタ2 movb $0x0, %ch movb $0x0, %dh movb $0x02, %cl //10シリンダ分読み込む readloop: // エラーカウンター movw $0x00, %si retry: //Disk読み出しのBIOSコール movb $0x02, %ah movb $0x01, %al movw $0x00, %bx movb $0x00, %dl int $0x13 jnc next //エラー処理 addw $0x01, %si // retry5回でエラー終了 cmp $0x05, %si jae error // ドライブを初期化 mov $0x00, %ah mov $0x00, %dl jmp retry next: //格納場所のアドレスを0x0020進める movw %es, %ax addw $0x0020, %ax movw %ax, %es add $0x01, %cl cmp $18, %cl jbe readloop movb $0x01, %cl addb $0x01, %dh cmp $0x02, %dh jb readloop movb $0x01, %dh add $0x01, %ch cmpb $10, %ch jb readloop // カーネルイメージが、読み込まれている // アドレスにジャンプする jmp 0x00c200 fin: hlt jmp fin error: movw $err_msg, %si call printstr jmp fin printstr: nop putloop: // SIで指定された文字列を // 1文字ずつ取り出す。 movb (%si), %al addw $0x01, %si // NULL文字か比較 cmpb $0x00, %al je putloop_end // SystemCallの設定 movb $0x0E, %ah movw $0x0015, %bx int $0x10 jmp putloop putloop_end: ret err_msg: .byte 0x0a,0x0a .ascii "Disk Error\r\n" .byte 0x00 .org 0x1fe .byte 0x55,0xaa
iplである程度、kernelに相当する部分をメモリ上に読み込んでおく。
.code16 .global _start _start: // レジスタを初期化する movw $0x00, %ax movw %ax, %ds movw %ax, %es movw %ax, %ss // 32ビットモードを有効にするために // PICをマスクする movb $0xff, %al outb %al, $0x21 nop outb %al, $0xa1 // 割り込みフラグをクリア cli // A20Gateを有効にする。 //割り込みを禁止する call waitkbout movb $0xd1, %al outb %al, $0x64 call waitkbout movb $0xdf, %al outb %al, $0x60 call waitkbout .arch i486 to_protect: // Protectモードにする lgdtl (gtr0) movl %cr0, %eax and $0x7ffffff, %eax or $0x0000001, %eax movl %eax, %cr0 jmp pipelineflash pipelineflash: movw $0x8, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %gs movw %ax, %ss // osmainを0x00280000にコピー movl $osmain, %esi movl $0x00280000, %edi movl $512 * 1024 / 4, %ecx call _memcpy jmp $0x10, $0x00000001 _fin: hlt jmp _fin waitkbout: inb $0x64, %al andb $0x02, %al jnz waitkbout ret // Memory Copy // Source : esi // Destination: edi // Counter: ecx _memcpy: movl (%esi), %eax add $4, %esi movl %eax, (%edi) add $4, %edi sub $1, %ecx jnz _memcpy ret .align 8 gdt0: // GlobalDescriptor Table // Null Selecter .skip 8, 0x00 // 1st GDT .word 0xffff, 0x0000, 0x9200, 0x00cf // 2nd GDT .word 0xffff, 0x0000, 0x9a28, 0x0047 // Last GDT .word 0x0000 gtr0: .word 8 * 3 - 1 .int gdt0 osmain: nop hlt jmp osmain
動作確認には、bochsを利用。
00442040000i[CPU0 ] CPU is in protected mode (halted) 00442040000i[CPU0 ] CS.d_b = 32 bit 00442040000i[CPU0 ] SS.d_b = 32 bit 00442040000i[CPU0 ] EFER = 0x00000000 00442040000i[CPU0 ] | RAX=0000000000000000 RBX=0000000000000015 00442040000i[CPU0 ] | RCX=0000000000000000 RDX=0000000000000100 00442040000i[CPU0 ] | RSP=0000000000007c00 RBP=0000000000000000 00442040000i[CPU0 ] | RSI=000000000008c2a8 RDI=0000000000300000 00442040000i[CPU0 ] | R8=0000000000000000 R9=0000000000000000 00442040000i[CPU0 ] | R10=0000000000000000 R11=0000000000000000 00442040000i[CPU0 ] | R12=0000000000000000 R13=0000000000000000 00442040000i[CPU0 ] | R14=0000000000000000 R15=0000000000000000 00442040000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf ZF af PF cf 00442040000i[CPU0 ] | SEG selector base limit G D 00442040000i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D 00442040000i[CPU0 ] | CS:0010( 0002| 0| 0) 00280000 0007ffff 0 1 00442040000i[CPU0 ] | DS:0008( 0001| 0| 0) 00000000 ffffffff 1 1 00442040000i[CPU0 ] | SS:0008( 0001| 0| 0) 00000000 ffffffff 1 1 00442040000i[CPU0 ] | ES:0008( 0001| 0| 0) 00000000 ffffffff 1 1 00442040000i[CPU0 ] | FS:0008( 0001| 0| 0) 00000000 ffffffff 1 1 00442040000i[CPU0 ] | GS:0008( 0001| 0| 0) 00000000 ffffffff 1 1
で、どこでハマっていたかというと、far jmpするところ。far jmpがうまくいかずにコードセグメントがなかなか32bitになってくれませんでした。
QEMUとGDBを使ったデバッグ
OSのデバッグ手法。
32bitモードに突入してしまうと、printfも簡単にはできなくなってしまいます。
qemu -S -s -m32 -localtime -fda os.img &
で、起動して
$ gdb
(gdb) target remote localhost:1234
(gdb) set architecture i8086
(gdb) break *0x07c00
(gdb) c
こんな感じで、IPLからデバッグできます。
参考図書
- 作者: 川合秀実
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2006/03/01
- メディア: 単行本
- 購入: 36人 クリック: 735回
- この商品を含むブログ (299件) を見る
- 作者: Arnold Robbins,千住治郎
- 出版社/メーカー: オライリージャパン
- 発売日: 2005/09/08
- メディア: 単行本(ソフトカバー)
- 購入: 2人 クリック: 39回
- この商品を含むブログ (22件) を見る
画面モードの切り替えまで
画面をグラフィックモードにするところまで出来ました。
ipl.s
// kawas Initial Program Loader // This program is going to be loaded at 0x7c00 cyls = 10 base_address: .code16 JMP entry // for FAT12 .byte 0x90 .ascii "HelloIpl" .word 512 .byte 1 .word 1 .byte 2 .word 224 .word 2880 .byte 0xf0 .word 9 .word 18 .word 2 .int 0 .int 2880 .byte 0,0,0x29 .int 0xffffffff .ascii "HELLO-OS " .ascii "FAT12 " .skip 18,0 entry: // Set Stack Segment to 0 movw $0, %ax movw %ax, %ss movw $0x7c00, %sp movw %ax, %dx // Read the disk movw $0x0820, %ax movw %ax, %es // set Sylinder 0 header 0 sector 2 movb $0, %ch movb $0, %dh movb $2, %cl readloop: // clear error counter movw $0, %si retry: movb $0x02, %ah movb $1, %al movw $0, %bx movb $0x00, %dl int $0x13 jnc next // add error counter add $1, %si // if error counter is over 5, print error message cmp $5, %si jae error movb $0x00, %ah mov $0x00, %dl int $0x13 jmp retry next: // 0x200 address is advanced. movw %es, %ax add $0x0020, %ax movw %ax, %es add $1, %cl cmp $18, %cl jbe readloop movb $1, %cl add $1, %dh cmp $2, %dh jb readloop movb $0, %dh add $1, %ch cmp $cyls, %ch movw $cyls, 0x0ff0 // Jump to main program JB readloop jmp 0xc200 fin: hlt jmp fin error: movw $0x00, %ax movw %ax, %es movw $msg, %si putloop: movb (%si), %al add $0x01, %si cmpb $0x00, %al je fin movb $0x0e, %ah movw $0x0015, %bx int $0x10 jmp putloop msg: .byte 0x0a,0x0a .ascii "load error" .byte 0x0a .byte 0x00 .org 0x1fe .byte 0x55,0xaa
ipl.ls
OUTPUT_FORMAT(binary) OUTPUT_ARCH(i386) SECTIONS { . = 0x7c00; .text : { *(.text) } }
main.s
// Set VGA to 320 x 200 x 8bit movb $0x13, %al movb $0x00, %ah int $0x10
main.ls
OUTPUT_FORMAT(binary) OUTPUT_ARCH(i386) SECTIONS { . = 0xc200; .text : { *(.text) } }
で、
as ipl.s -o ipl.o as main.s -o main.o ld ipl.o -T ipl.ls -o ipl.bin ld main.o -T main.ls -o main.bin mfotmat -f 1440 -C -B ipl.bin -i osimage.img :: mcopy -i osimage.img main.bin
こんな感じで。
レジスタのお勉強
とりあえず、自作OSにアセンブラを使うが、だいぶ、忘れてしまったので、復習をかねて。いまさらアセンブラかよ!
レジスタ。
32ビット(DoubleWord)
EAX(アキュレータ(累積演算))
ECX(カウンタ)
EDX(データ)
EBX(ベース)
ESP(スタックポインタ)
EBP(ベースポインタ)
ESI(ソースインデックス)
EDI(ディストネーションインデックス)
16ビット(Word)
AX
CX
DX
BX
SP
BP
SI
DI
8ビット(Byte)
AL,AH
CL,CH
DL,DH
BL,BH
セグメントレジスタ
ES(エクストラセグメント)
CS(コードセグメント)
SS(スタックセグメント)
DS(データセグメント)
FS
GS