2014年9月26日金曜日

latexmkの最も敷居の低い使い方

makefile を作ります。

all:
clean:
        latexmk -c hoge.tex

latexmk を設定しなくても make clean を簡単に作れます。おわり。 

……これ地味に見えるんですが、rmとアスタリスクの組み合わせが招く不幸を防げるという点でとてもありがたいと思いました。-c にするか -C にするかはお好みで。

2014年9月23日火曜日

uim-mozcをパッケージに触らず無効化する方法

システムワイドに uim-mozc が入っていて、uim-anthy を入れるからmozcは無効化したい、でもパッケージは削除したくない…… そんなシチュエーションに遭遇する人はあまりいないと思いますが、そんなときは uim から mozc を無効化しましょう。 システム全体に影響する変更方法はこちら。


# uim-module-manager --unregister mozc --path /var/lib/uim
で、このコマンドを探し当てるためにまた遠回りしたので、その経緯を書いておきます。

まず、uim の仕組みが分かっていなかったので、とりあえずなにかファイルを消せばいいと思った(強引)のですが

% dpkg -L uim-mozc
/.
/usr
/usr/lib
/usr/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu/uim
/usr/lib/x86_64-linux-gnu/uim/plugin
/usr/lib/x86_64-linux-gnu/uim/plugin/libuim-mozc.so
/usr/share
/usr/share/uim
/usr/share/uim/pixmaps
/usr/share/uim/mozc.scm
/usr/share/uim/mozc-custom.scm
/usr/share/uim/mozc-key-custom.scm
/usr/share/doc
/usr/share/doc/uim-mozc
/usr/share/doc/uim-mozc/README.Debian
/usr/share/doc/uim-mozc/copyright
/usr/share/doc/uim-mozc/changelog.Debian.gz
/usr/share/lintian
/usr/share/lintian/overrides
/usr/share/lintian/overrides/uim-mozc
/usr/share/uim/pixmaps/mozc_tool_dictionary_tool.png
/usr/share/uim/pixmaps/mozc.png
/usr/share/uim/pixmaps/mozc_tool_selector.png
/usr/share/uim/pixmaps/mozc_tool_config_dialog.png

当然、なにを消して良いかこれだけで理解するのは無理というもの。

そういえばdebian にはパッケージのコントロールファイルがあるじゃないか。それを見よう、と思い立つわけです。

% dpkg -e uim-mozc_1.5.1090.102-4+deb7u1_amd64.deb ~/tmp-uimcontrol
% cd ~/tmp-uimcontrol
% ls -la
total 44
drwxr-xr-x   2 tarai staff  4096 Jun  7  2013 .
drwx------ 140 tarai staff 20480 Sep 23 17:49 ..
-rw-r--r--   1 tarai staff  1010 Jun  7  2013 control
-rw-r--r--   1 tarai staff   560 Jun  7  2013 md5sums
-rwxr-xr-x   1 tarai staff  1504 Jun  7  2013 postinst
-rwxr-xr-x   1 tarai staff   132 Jun  7  2013 postrm
-rwxr-xr-x   1 tarai staff   985 Jun  7  2013 prerm
-rw-r--r--   1 tarai staff    21 Jun  7  2013 shlibs
% lv postinst
(中略)
    configure)
        if which uim-module-manager >/dev/null 2>&1; then
                uim-module-manager --register mozc --path /var/lib/uim
        fi
    ;;
(以下略)
% lv prerm
(中略)
    remove|deconfigure)
        if which uim-module-manager >/dev/null 2>&1; then
                uim-module-manager --unregister mozc --path /etc/uim
        fi
        ;;
(以下略)

postinst や prerm の詳細は http://www.debian.or.jp/community/devel/debian-policy-ja/policy.ja.html/ch-maintainerscripts.html が詳しいです。

つまりこの uim-module-manager というコマンドが重要なんですね、というところにたどりつき、 冒頭のような操作で大丈夫だろう、という結論に到達した次第です。
(何故postinstとprermで pathの引数が違うんだろう……)

2014年6月23日月曜日

スマフォの写真を LaTeX で書いてるレポートにepsで貼りたい人

簡単に言うと「スマフォの写真画像は大きすぎるので縮小しましょう。そしてepsにしたいなら convert (ImageMagick) ではなく sam2p を使いましょう」という話。
説明はいいからコマンド寄越せって人向けに、picture.jpg を figure.eps に変換するにはこうしろ!と書いておきます。例によって% はプロンプトです。画像は横長と仮定します。

% convert -resize 640x picture.jpg figure.jpg
% sam2p figure.jpg figure.eps

ファイルが複数ある場合はいろいろ仕掛けを考えて下さい。(説明を読まない人向けの数値設定にしてみました。)


以下解説。


まず貼りたい写真の素性を明らかにしておきましょう。とりあえず横長の画像であることを前提にしておきます。 ImageMagick が入っているなら identify もあるはず。

% identify picture.jpg
picture.jpg JPEG 2112x1500 2112x1500+0+0 8-bit DirectClass 401KB 0.000u 0:00.000

最近のスマフォの写真は解像度が高いので、必然的に写真のファイルサイズも大きくなりがちです。 が、そんなに大きくなくていいんじゃないですか? 本当にそんな解像度要りますか? 横幅2112pixelって、300dpiなら確かに17.9センチとA4縦のレポートに1枚貼るには程よいサイズですけど、 その写真、そんな印刷品質で出さないと内容が伝わらないほど細かい情報、ありますか?

例えばこれくらいのサイズでいかがでしょうか。

% convert -resize 800x picture.jpg figure.jpg

横長の画像を前提にしていますが、もし縦長なら -resize x800 でしょうか。 72dpiでも21.1cm程度の画像になりますから、これくらいでも十分に思えます。
pdfにするときも、縮小したものを貼るほうが何かとトラブルが少なくてよいでしょう。 
で、これをepsに変換するわけですから、convertを使えばコマンド1つで、例えば

% convert -resize 800x picture.jpg eps2:figure.eps

とすれば良さそうなものなのですが、どうもこのconvertが作るepsファイルがいまいちプリンタとの相性が良くないのです。 プリンタとの相性が悪いのかプリンタドライバとの相性が悪いのか、とにかく RICOH Ridoc IOGate (RHEL版) で管理されているプリンタでよく印刷が止まります。大学などの演習室で利用実績のあるプリンタ管理ソフトウェアですので、 たとえば演習室でレポートがうまく印刷出来ない場合はこれを疑ってよいと思います。

というわけで代案は、sam2pコマンドを使うことです。入ってなければ入れてもらいましょう。 sam2p はリサイズ機能を持っていませんので、convertで縮小してから、

% sam2p figure.jpg figure.eps

これで変換した figure.eps を貼ることをお勧めします。

いまどきepsもないだろう、と思われる方でも、せめてjpg画像のサイズには気を遣った方がいいと思います。 スマフォの写真を何も考えずに貼ると、pdfファイルのサイズが肥大化します。気をつけましょう。

2014年6月9日月曜日

C言語で一様乱数を作ろうとしてうっかりする

C言語で乱数を発生させるときによく使う「0以上1未満の一様乱数を作る」方法なのですが、適当にインターネットからコピペして使っていると、編集ミスなどをやらかしヒドイ目に遭うようです。型変換を理解せず、コンパイラの警告も適当に流して使ったりすると、そういうことになるので、学生さんは気をつけましょう、という話。

 まずは12個、パターンを列挙してみます。

double randnnA(){
 return rand() / (RAND_MAX + 1);
}

double randnnB(){
 return rand() / (RAND_MAX + 1.0);
}

double randndA(){
 return rand() / (double)(RAND_MAX + 1);
}

double randndB(){
 return rand() / (double)(RAND_MAX + 1.0);
}

double randndC(){
 return rand() / ((double)RAND_MAX + 1);
}

double randndD(){
 return rand() / ((double)RAND_MAX + 1.0);
}

double randdnA(){
 return (double)rand() / (RAND_MAX + 1);
}

double randdnB(){
 return (double)rand() / (RAND_MAX + 1.0);
}

double randddA(){
 return (double)rand() / (double)(RAND_MAX + 1);
}

double randddB(){
 return (double)rand() / (double)(RAND_MAX + 1.0);
}

double randddC(){
 return (double)rand() / ((double)RAND_MAX + 1);
}

double randddD(){
 return (double)rand() / ((double)RAND_MAX + 1.0);
}
コンパイル可能なソースコードはこちら。
https://gist.github.com/taraijpn/7789f5e5382a2111a6c4
(動作を確認するため若干いじってあります。)

おかしな動きをする関数が4つあるのですが、分かりますでしょうか? 

A で終わっている関数は全て挙動が不適切になります。

$ ./a.exe
set 0 and RAND_MAX
randnnA min:0    max:0
randnnB min:0    max:0.9999999995343387
randndA min:-0   max:-0.9999999995343387
randndB min:0    max:0.9999999995343387
randndC min:0    max:0.9999999995343387
randndD min:0    max:0.9999999995343387
randdnA min:-0   max:-0.9999999995343387
randdnB min:0    max:0.9999999995343387
randddA min:-0   max:-0.9999999995343387
randddB min:0    max:0.9999999995343387
randddC min:0    max:0.9999999995343387
randddD min:0    max:0.9999999995343387

generate random number 10000 times
randnnA min:0    max:0
randnnB min:0.0001787277869880199        max:0.9999335804022849
randndA min:-0.9998125517740846          max:-0.0001268410123884678
randndB min:6.128335371613503e-05        max:0.9999860003590584
randndC min:1.606764271855354e-05        max:0.99976617237553
randndD min:6.103422492742538e-06        max:0.9999661864712834
randdnA min:-0.9998871022835374          max:-3.686733543872833e-05
randdnB min:2.388842403888702e-07        max:0.9999870401807129
randddA min:-0.9999983948655427          max:-2.792663872241974e-05
randddB min:5.736947059631348e-05        max:0.9998592492192984
randddC min:3.99700365960598e-05         max:0.9999427762813866
randddD min:8.147209882736206e-05        max:0.999992452096194

randnnAがダメな理由、まあどちらもintだし、というところまでは想像つくと思いますが、何故(RAND_MAX)/(RAND_MAX+1)がdouble型に代入されると0.0になるのか、はちょっと説明に引っかかるかも? また、なにか演算した後にあわてて型変換しても手遅れ(randndAがダメ)なことも分かります。

それと、分子側が(double)で型変換されてれば問題ないだろ、と思ってしまうのもいけません(randdnA, randddAがダメ)です。 [0,1)の一様乱数を作ろうとしているのに負の値が出てる時点で何かおかしいと気づくだろうと思います。

CとDは分母の (double)RAND_MAX でdouble型になるので、これに1を足そうが1.0を足そうがいずれにせよdouble型であることは変わりません。書く意味はほとんどなかったかも。まあパターンで列挙した次第です。

gccのバージョンが新しめならコンパイラがWarningで教えてくれるようですので、 Warningは見落とさないようにしましょう。

$ gcc --version
gcc (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gcc urandtest.c
urandtest.c: In function ‘randnnA’:
urandtest.c:8:24: warning: integer overflow in expression [-Woverflow]
  return ir / (RAND_MAX + 1);
                        ^
urandtest.c: In function ‘randndA’:
urandtest.c:18:32: warning: integer overflow in expression [-Woverflow]
  return ir / (double)(RAND_MAX + 1);
                                ^
urandtest.c: In function ‘randdnA’:
urandtest.c:38:32: warning: integer overflow in expression [-Woverflow]
  return (double)ir / (RAND_MAX + 1);
                                ^
urandtest.c: In function ‘randddA’:
urandtest.c:48:40: warning: integer overflow in expression [-Woverflow]
  return (double)ir / (double)(RAND_MAX + 1);
                                        ^
4.7でもいけました。コンパイラのバージョンが古かったり32bit環境だったりすると、なんとなく正しく動くものが増えるところが厄介です。
個人的には、ちょっと使う時には Mersenne Twister with improved initialization (2002) をお勧めしています。 本格的に使う場合は改良版(SFMT)の導入を検討したほうがよいでしょう。

おまけ。

double lrandnnA(){
 return rand() / (RAND_MAX + 1L);
}

double lranddnA(){
 return (double)rand() / (RAND_MAX + 1L);
}

整数リテラルってやつですね。それぞれ希望した結果になるでしょうか? ならないでしょうか?

2014年5月16日金曜日

nohupはどこにあるのか?

tcsh の場合 where を使ってみると、こうなります。(Debian Linuxで試しています。)
% where nohup
nohup is a shell built-in
/usr/bin/nohup
/usr/bin/X11/nohup
一方 bash の場合は where が無いので which -a を使ってみる。
$ which -a nohup
/usr/bin/nohup
/usr/bin/X11/nohup

というわけで、tcshのnohupはシェルビルトインコマンドであり、bashのそれは外部コマンドなのです。
そして挙動ですが、tcshの場合、manpageによると
デフォルトでは、シェルの子供たちもそうしますが、 シェルは終了時に HUP を子供たちに送りません。 hup はシェルが終了時に 子供に HUP を送るようにし、 nohup は子供がHUP を無視するように 設定します。
とのこと。一方bashの場合はshoptで確かめます。
$ shopt huponexit
huponexit       off
あれ? いずれにせよ、バックグラウンドジョブにhupが渡らないように見えます、 nohup無くても困らないんじゃない? などと思ってしまうのですが、実はそんな簡単な話でもないようです。

 技術 / UNIX / なぜnohupをバックグランドジョブとして起動するのが定番なのか?(擬似端末, Pseudo Terminal, SIGHUP他) http://www.glamenv-septzen.net/view/854

詳細についてはこちらの記事をお勧めします。勉強になります。