No Such Blog or Diary

«Prev || 1 | 2 | 3 |...| 56 | 57 | 58 || Next»

Prolog 怖い

リストの長さを意味する述語 p を作ろうかと思った人が次のコードを書いた.空リストの長さはゼロという意味で.

p([],O).

そして p([],N). とやって,N = 0 と返ってくることを期待してみると……

?- p([],N).
true.

期待と違う答えが返ってくる.何故だ……

ということで,このコードのデバッグに結構時間を食った.実際には元のプログラムはもう少し大きかったのだけど,本質的には上のコードのバグ探し.

んで,デバッグ後のコードは次のとおり.

p([],0).

つまり,大文字の O(オー)と 0(ゼロ)を間違えて書かれていたことに気が付かなかったというオチ.本人が最終的に気づいたので解決したけれど,本人がその場に居なかったら誰も気づかずにさらなる時間を無駄にしたに違いない.

まあ,紛らわしいフォントを使うのが悪い.プログラミングに使うって分かってんだから .emacs のひな形にプログラミングしやすいフォントを指定するよう書いておけばいいのに(学生が演習で使う端末室の計算機なのだから).

閑話休題.

O と 0 を書き間違えても正しいコードになるってのは高級言語ならではの面倒さかね.C言語やJavaではコンパイルエラー一発でしょう.

min(x, NaN) の扱いが違う罠

C++ のプログラムを Java に移植していてハマった罠.下の2つのプログラムは異なる値を出力する.

#include <iostream>
int main(int argc, char *argv[]) 
{
  std::cout << (std::min(1.0, 0.0/0));
  return 0;
}
import java.io.*;
import java.util.*;
class test {
    public static void main(String [] args) throws Exception {
    System.out.println(Math.min(1.0, 0.0/0));
    }
}

C++ だと min(x, NaN) == x っぽく,他方,Java だと min(x, NaN) == NaN っぽい.

Postscript で放物線を書く

簡単に書けると思ってたら意外と手間がかかった.検索しても答えが見つからんし.

ということで,3次ベジェ曲線の式と放物線の式と2時間くらい格闘した結果が以下の PS ファイル.とりあえず,PSTricks の \parabola に倣ってひとつの端点と放物線の頂点をパラメータに渡す関数 parabola を作ってみた.

%!PS-Adobe-3.0
%%BoundingBox: 0 -10 201 201
 
newpath 0 0 200 0 moveto lineto stroke
 
/parabola {
4 dict begin
/y3 exch def   % the top
/x3 exch def
/y0 exch def   % start point
/x0 exch def
% control point at the start point
/x1 x0 x0 x3 sub 3 div sub def
/y1 y0 y0 y3 sub 3 div 2 mul sub def
% control point at the top
/x2 x3 x0 x3 sub 3 div add def
/y2 y3 def
% end point
/x6 x3 x3 x0 sub add def
/y6 y0 def
% control point at the end point
/x4 x3 x6 x3 sub 3 div add def
/y4 y3 def
% control point at the top point
/x5 x6 x6 x3 sub 3 div sub def
/y5 y6 y6 y3 sub 3 div 2 mul sub def
% now, draw the parabola curve!
newpath x0 y0 moveto x1 y1 x2 y2 x3 y3 curveto x3 y3 moveto x4 y4 x5 y5 x6 y6 curveto stroke
end
} def
 
% specify the start and the top points
0 0 100 150 parabola
0 200 100 150 parabola
showpage

結局, P(t) = P0 (1-t)^3 + 3 P1(1-t)^2 t + 3 P2(1-t) t^2 + P3 t^3 という3次ベジェ曲線の式から,端点 P0 = P(0) と P3 = P(1) とそこでの微分 P'(0) と P'(1) とを指定してあげれば,制御点 P1 と P2 は P1 = P0 + P'(0)/3 と P2 = P3 - P'(1)/3 で決定できる.この微分値 P'(0) と P'(1) とを指定して描かせるのは面倒なので,放物線の頂点と他一点を与えることで方程式(y-y0 = a (x-x0)^2)を確定して,その方程式から(t = (x-x0)/(x3-x0)とでもして)計算してあげることにする.それが上のPSファイルの中身.んで,計算された制御点を使ってあげると任意の t in [0,1] でP(t)は指定した放物線になっている.

gcc の < regex > の正規表現の不思議

以下のプログラムは "G" という文字列が "A|T|G" という正規表現にマッチするかどうかを調べるもので,当然マッチするので ret=1 が期待する出力となる.

#include <regex>
#include <iostream>
using namespace std;
using namespace std::regex_constants;
 
int main(){
  regex r("A|T|G");
  string s("G");
  bool ret=regex_match(s,r);
  cerr << "ret=" << ret << endl;
}

が,いくつか試した gcc で出力が ret=1 になったのは svn 上の gcc (4.9.0 experimental) だけだった.Ubuntu 12.04 amd64 でソースからコンパイルした 4.8.2 でも ret=0 で,他に同Ubuntu の 4.6系 とソースからコンパイルした 4.7.2 もダメで,cygwin の 4.8.1 もダメだった.

Visual Studio では ret=1 になったらしい.Boost は大丈夫らしい.Mac の gcc のどれかも上の単純な例では大丈夫だったらしい.

どうも | で3つ以上つながると狂うらしい.まあ,Is gcc4.7 buggy about regular expressions? とかを見る限りだいぶ前からこの状況らしく,そもそも gcc (libstdc++) の regex は不完全であると.だがしかし,"A|T|G" とかいうレベルの単純な正規表現でもダメとか言うレベルの不完全さとか誰も想像できん.驚いた.

C++ の文字列リテラルを型に変換してメタプログラミングする方法

Using strings in C++ template metaprograms という記事を見つけた.

基本は「定数配列の定数要素アクセスは定数である」という仕様を使うのね.長さの違う文字列に効率的に対応するために,最長文字列長を決めといて,その文字列長に対応するマクロをプリプロセッサの繰り返しで作っておいて,短い奴に対応するために要素アクセスを constexpr な関数で条件付きにしてあると.

うーん.長さ制限をなくせる手法があると完璧なのだけど,無理かね.文字列リテラルの文字列長はコンパイル時には取れるけれどプリプロセスの時点では取れないか.

閑話休題.

constexpr な関数が普通の関数としてコンパイルできること,とかいう条件が邪魔だな…… コレのせいで constexpr な関数の引数をテンプレート引数に入れることができない.例えその関数が常に定数に対してしか使われないとしても.

定数に対してしか使えない関数を定義できる枠組みがあると便利そうだけどコンパイラが大変そうだなぁ.

ハマる

Coq の Module の Inline ディレクティブに関連して理解不能なエラーにハマった.下のコードがハマった部分を抜き出したもの.

Module Type A. End A.
Module Type B  (a : A). 
  Parameter t : Type.
End B.
Module Type Bi (a : A). 
  Parameter Inline(10) t : Type.
End Bi.
Module C  (b : B).  End C.
Module Ci (b : Bi). End Ci.
 
Module CX (b : B) (bi : Bi).
  (* These two work well.*)
  Module Cb := C b.
  Module Cbi := C bi. 
  (* These two work well too, using `!' to ignore the Inline directive. "*)  
  Module Cib := !Ci b.
  Module Cibi := !Ci bi.
  (* This fails with saying "Error: The field t is missing in Top.b."*)  
  Module Cib2 := Ci b.
  (* This fails with saying "Error: The field t is missing in Top.bi."*)  
  Module Cibi2 := Ci bi.
End CX.

ファンクタ B と Bi は Print Module Type で見ても名前以外は同じ.ファンクタ C と Ci はファンクタ B と Bi をとる.んで,この C と Ci に B と Bi の型の b と bi を適用してみると,Inline を付けた定義の Bi を受け取るという定義の Ci に関してよくわからんエラーが出る.b も bi も t というフィールドを持っているのにそれが無いとか言われ…… 

とりあえず ! 付けて Inline を無視させればエラーでないということは学習した.でも Inline の意味はよくわからん.

«Prev || 1 | 2 | 3 |...| 56 | 57 | 58 || Next»
Search
Feeds

Page Top