ばいなり絶望電卓

ついでに、もうひとつさよなら絶望放送ネタを。
この投稿の「水澄」さんという絶望ネームもいろんな意味で惹かれるんですが、それはさておき。

「2 ÷ 3 × 3」を計算機で計算すると、答えが「2」と出る計算機と、「1.99999999999」と出る計算機があります。
きつちりしてもらいたいものです。

http://www.animate.tv/digital/web_radio/detail_104.html

という「きつちりしなさい!」の投稿でスタジオ内で起きてた騒動についてちょっと真面目に考えてみようかな、と。
我々だと普通に流しがちですが、掘り進むと色々見えてくるお話のような気がするのです。これが。


ちなみに、番組内では神谷浩史さんも新谷良子さんもスタッフの皆さんも微妙に混乱していました。特に新谷さん、落ち着け。

絶望放送内での結果

まず、絶望放送中スタジオで皆さんが携帯電話付属の計算機で確かめた結果は以下の通り。

神谷浩史携帯
1.9999999
新谷良子携帯(2台)、ディレクター携帯
1.99999999998
構成作家T携帯
2.000001

だいぶ実装が違います。ちなみに新谷さんの携帯は両方とも SHARP 製っぽいです。豆知識。
神谷さんがぼそっと言ってる

神谷浩史
「2÷3」をまずやると、0.666.... になんだよね。それを掛けちゃうからってことなのかなぁ。
http://www.animate.tv/digital/web_radio/detail_104.html

で一般常識的には問題ないんですが、こちとらお仕事なのでそれだけで終わりたくないのです。
特に、構成作家T氏の「2.000001」とか。何か変な丸め誤差対策をやってる気がする気がしてとても気になるし。


ちなみに、この中で一番素直な実装なのはたぶん神谷さんの携帯。少し大きめに取った浮動小数点演算結果を表示だけ切り詰めたんだと思います。
新谷さんの携帯は、内部実装で桁数いっぱい保持していて 0.66666666666 × 3.0 になったと考えるのが普通ですが、なんか浮動小数点演算的にひっかかるなぁ、と。
で、一番謎な構成作家T氏の携帯。普通に考えると 0.666667 × 3.0。途中の演算結果を四捨五入して、ついでにその結果をそのまんま保持してる感じでしょうか。なんか色々中途半端な実装ではあります。


てことで絶望放送スタッフの珍妙な結果はさておき、ちゃんとした実装の方を。

手元の実装系においての結果

我が家の環境は MacLeopard)と Gentoo Linux x86 の二種類あるので、それぞれでの結果を出してみます。
ちなみに整数演算時に 0 が返るのはご存じの通り*1


まず、Python は型に厳密なためそのまま書くと整数と解釈されて 0 が返ります。
浮動小数点指定してやると、最近の Python は 2.0 を返してくれます。

$ python
Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 / 3 * 3
0
>>> 2.0 / 3.0 * 3.0
2.0
$ python
Python 2.4.4 (#1, Apr 26 2008, 13:25:51) 
[GCC 4.1.2 20070214 (  (gdc 0.24, using dmd 1.020)) (Gentoo 4.1.2 p1.1)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 / 3 * 3
0
>>> 2.0 / 3.0 * 3.0
2.0


Ruby でも数値の型判定は厳密に行われ、同じ結果が返ってくるようです。irb で簡単に調べただけですが。

$ ruby -v
ruby 1.8.6 (2007-09-24 patchlevel 111) [universal-darwin9.0]
$ irb
>> 2 / 3 * 3
=> 0
>> 2.0 / 3.0 * 3.0
=> 2.0
$ ruby -v
ruby 1.8.6 (2008-03-03 patchlevel 114) [i686-linux]
$ irb
>> 2 / 3 * 3
=> 0
>> 2.0 / 3.0 * 3.0
=> 2.0


Perl の場合はこんな感じで型如何に関わらず 2 が返ります。さすが Perl 。実は print ステートメントの仕様かも?

$ perl -v

This is perl, v5.8.8 built for darwin-thread-multi-2level
(with 1 registered patch, see perl -V for more detail)

Copyright 1987-2006, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

$ perl -e 'print 2 / 3 * 3'
2
$ perl -e 'print 2.0 / 3.0 * 3.0'
2
$ perl -v

This is perl, v5.8.8 built for i686-linux

Copyright 1987-2006, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

$ perl -e 'print 2 / 3 * 3 '
2
$ perl -e 'print 2.0 / 3.0 * 3.0'
2


以上、LL ではちゃんと浮動小数点演算時に 2.0 もしくは 2 が返ります。さすがというか何というか。


……と、今日のところはこのへんにしておきます。
とりあえず明日は、32ビット整数と32ビット浮動小数点に的を絞って考えてみます。IEEE 754 読まねば。

*1:説明は要らないと思いますが、整数演算は切り捨てなので 2 ÷ 3 = 0 になります