[Armadillo:08318] Perl-5.8.8 をArmadillo-4x0で動かすと実数がおかしくなる

Yasuhisa Nakamura email@hidden
2012年 9月 12日 (水) 18:30:25 JST


中村です。

ちょっと長いです。

ずいぶん前の記事になりますが、[Armadillo:06167]
http://lists.atmark-techno.com/pipermail/armadillo/2010-November/006167.html
で、Perl-5.8.8をatmark-distでビルドできるようにするパッチが
竹之下さんにより投稿されていました。

これを使えばPerlでCGIや単独スクリプトなど簡単に書けるようになり、
便利に使わせていたいだています。
竹之下さん、ありがごうございます。

5.8.8と、かなり古いバージョンですから、今でもこのバージョンを
使われている方が現在どのくらいいるのかわかりませんが、
Armadillo-4x0で使っていて、実数で次のような不具合がありましので、
その現象と対処方法をお知らせします。

次のものは正常です。
perl -e 'print 1327402000+0,"\n"'
1327402000
perl -e 'print 1327402000+10,"\n"'
1327402010
perl -e 'print 1327402000+100,"\n"'
1327402100
perl -e 'print 1327402000+1000,"\n"'
1327403000

実数にすると、次のようにおかしくなります。
perl -e 'print 1327402000+0.0,"\n"'
1327401984.24578
perl -e 'print 1327402000+10.0,"\n"'
1327401984.24578
perl -e 'print 1327402000+100.0,"\n"'
1327401984.24578
perl -e 'print 1327402000+1000.0,"\n"'
1327401984.24578

perl -e 'print 1327402000.0,"\n"'
1327401984.24577
perl -e 'print 1327402010.0,"\n"'
1327401984.24577
perl -e 'print 1327402100.0,"\n"'
1327401984.24577
perl -e 'print 1327403000.0,"\n"'
1327401984.24577

これら結果の"1327401984.24578"や"1327401984.24577"の
小数点以下の部分".24578"や".24577"は、ビルドしなおすと
これとは異なる表示になりますので、ゴミを拾っている感じです。

// 1327402000という数値は、この問題に遭遇したときに
// 使っていた値で、特別な意味はありません。

この現象は、Perl-5.8.8のオリジナルソースをデフォルトのまま
(Perl-5.8.8のソースを展開しただけの状態で)
次のようにクロスコンパイルしたmicroperlでは発生ません。
  make -f Makefile.micro CC=/usr/bin/arm-linux-gnueabi-gcc

しかし、最適化の"-O2"をつけて、
  make -f Makefile.micro CC=/usr/bin/arm-linux-gnueabi-gcc OPTIMIZE=-O2
としてビルドしたmicroperlでは、同じ症状が発生します。

Armadillo-220(ATDE2環境)では"-O2"をつけてもこの問題は発生しません。

また、ATDE3環境でx86用として
  make -f Makefile.micro OPTIMIZE=-O2
としたmicroperlを使った場合も問題は出ません。

gccのバージョンは、
Armadillo-220の開発環境ATDE2
 gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
Armadillo-400の開発環境ATDE3(x86用のgccもarm-linux-gnueabi-gccも)
 gcc version 4.3.2 (Debian 4.3.2-1.1)
でした。

Armadillo-4x0の開発環境であるATDE3に入っているarm用gccの
最適化のバグか、あるいは、最適化の影響を受けて誤動作する
コードがperlのソースにあるものと思われます。

たくさんあるperlのソースコードの中で問題となっているものを
探してたところ、sv.cにだけ"-O2"を付かなければ、この問題を
回避できることがわかりました。

竹之下さんさんのパッチを使ってatmark-distに組み込んだperl-5.8.8を
ビルドする場合には、cflags.SHに次のパッチをあてれば、
sv.cだけ最適化をナシ("-O0")にすることができます。

--- src/atmark-dist/trunk/user/perl/cflags.SH-orig
+++ src/atmark-dist/trunk/user/perl/cflags.SH
@@ -113,11 +113,11 @@
     pp_sys) ;;
     regcomp) ;;
     regexec) ;;
     run) ;;
     scope) ;;
-    sv) ;;
+    sv) optimize=-O0;;
     taint) ;;
     toke) ;;
     usersub) ;;
     util) ;;
     *) ;;

なお、perl-5.8.9ではこの問題は発生しませんでした。
perl-5.8.8とperl-5.8.9のsv.cを見比べてみましたが、
5.8.8から5.8.9でかなりの修正がなされており、sv.cの中の
どこが問題になっていたのか?までは特定できていません。
(この特定ができれば、今後自分でArmadillo-4x0用のCの
プログラムを書くときに、こういう書き方をしたら環境や
最適化依存のバグになる、というのがわかるのですが・・・)

perl-5.10.1でmicroperlをクロスコンパイルしたものでも
"-O2"のこの問題は発生しませんでした。
それ以降のperl(5.12.x以降)は、上に書いた方法での
microperlのクロスコンパイルができなくなってしまっているので、
試していません。

Armadillo-4x0でperl-5.8.8をお使いの方のお役にたてれば、
幸いです。

-- 
なかむら




armadillo メーリングリストの案内