今さら丸めの話
265=36893488147419103232の次に大きいIEEE64bit浮動小数点数は265+213=36893488147419111424です。仮に、265+212+1=36893488147419107329を浮動小数点数に丸めるとしたら、IEEE754を持ち出すまでもなく表現できる中で最も近い浮動小数点数に丸めるのが自然でしょうから、265+213になるはずです。では実際に試してみましょう。
$ php -r 'printf("%21.0f\n",36893488147419107329);' 36893488147419111424 $ perl -e 'printf("%21.0f\n",36893488147419107329);' 36893488147419103232 $ ruby -e 'printf("%21.0f\n",36893488147419107329);' 36893488147419103232 $ python -c 'print "%21.0f\n" % 36893488147419107329;' 36893488147419103232
ふむふむ。きむら(K)さんの書いている strtod、round の話はおいておいて、うちの環境でも試してみよう。
% cat test.sh #!/bin/sh echo 'integer literal' echo -n 'php4 '; php4 -r 'printf("%21.0f\n",36893488147419107329);' echo -n 'php5 '; php5 -r 'printf("%21.0f\n",36893488147419107329);' echo -n 'perl '; perl -e 'printf("%21.0f\n",36893488147419107329);' echo -n 'ruby '; ruby -e 'printf("%21.0f\n",36893488147419107329);' echo -n 'python'; python -c 'print "%21.0f\n" % 36893488147419107329;' echo 'floating literal' echo -n 'php4 '; php4 -r 'printf("%21.0f\n",36893488147419107329.0);' echo -n 'php5 '; php5 -r 'printf("%21.0f\n",36893488147419107329.0);' echo -n 'perl '; perl -e 'printf("%21.0f\n",36893488147419107329.0);' echo -n 'ruby '; ruby -e 'printf("%21.0f\n",36893488147419107329.0);' echo -n 'python'; python -c 'print "%21.0f\n" % 36893488147419107329.0;' % sh test.sh integer literal php4 36893488147419110000 php5 36893488147419110000 perl 36893488147419103232 ruby 36893488147419111424 python 36893488147419111424 floating literal php4 36893488147419110000 php5 36893488147419110000 perl 36893488147419103232 ruby 36893488147419103232 python 36893488147419111424
うぇ。全然違う結果が出ております。
で、まぁそれぞれの言語で適当に仮数部のビット列を求めてみたりするわけです。
import sys def significand(f): f = float(f) while 1.0 < f: f /= 2.0 if f == 1.0: return (1,) ret = [] while f > 0: f *= 2 if f >= 1.0: ret.append(1) f -= 1.0 else: ret.append(0) return ret if __name__ == '__main__': print ''.join(str(i) for i in significand(sys.argv[1]))
<?php function significand($f) { while ($f > 1.0) { $f /= 2.0; } if ($f == 1.0) { return array(1); } $ret = array(); while ($f > 0.0) { $f *= 2; if ($f >= 1.0) { $ret[] = 1; $f -= 1.0; } else { $ret[] = 0; } } return $ret; } echo implode('', significand(doubleval($argv[1]))), "\n"; ?>
use strict; use warnings; use Perl6::Say; sub significand { my $f = shift; while ($f > 1.0) { $f /= 2.0; } return 1 if $f == 1.0; my @ret; while ($f > 0.0) { $f *= 2.0; if ($f >= 1.0) { push @ret, 1; $f -= 1.0; } else { push @ret, 1; } } return @ret; } if ($0 eq __FILE__) { say join '', significand($ARGV[0]); }
def significand(f) while f > 1.0 f = f / 2.0 end return [1] if f == 1.0 ret = [] while f > 0.0 f *= 2.0 if f >= 1.0 ret << 1 f -= 1.0 else ret << 0 end end return ret end if $0 == __FILE__ puts [significand(ARGV[0].to_i).join, significand(ARGV[0].to_f).join].join(' ') end
Ruby は整数リテラルと浮動小数点数リテラルで結果が違ったのでそれぞれテスト。
で、
% cat test2.sh echo -n 'php4 '; php4 significand.php 36893488147419107329 echo -n 'php5 '; php5 significand.php 36893488147419107329 echo -n 'python '; python significand.py 36893488147419107329 echo -n 'perl '; perl significand.pl 36893488147419107329 echo -n 'ruby '; ruby significand.rb 36893488147419107329 % sh test2.sh php4 10000000000000000000000000000000000000000000000000001 php5 10000000000000000000000000000000000000000000000000001 python 10000000000000000000000000000000000000000000000000001 perl 1 ruby 10000000000000000000000000000000000000000000000000001 1
実際には正規化されるので、ぞれぞれ先頭の1は内部的には保持してないんだけど、まぁそれは本質的な話ではないのでおいておいて、出力結果は違っても実は内部的には同じ数字なんじゃあるまいか(Perl 除く)。id:hnw さんのところではどうなるだろう。
一応、id:hnw さんにならって環境を晒し。libc は glibc-2.3.6。
% uname -mrs Linux 2.6.18-4-xen-amd64 x86_64 % perl -v This is perl, v5.8.8 built for x86_64-linux-gnu-thread-multi 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. % python -V Python 2.5.1 % ruby -v ruby 1.8.6 (2007-06-07 patchlevel 36) [x86_64-linux] % php4 -v PHP 4.4.4-8+etch4 (cli) (built: Jun 30 2007 14:58:42) Copyright (c) 1997-2006 The PHP Group Zend Engine v1.3.0, Copyright (c) 1998-2004 Zend Technologies % php5 -v PHP 5.2.0-8+etch7 (cli) (built: Jul 2 2007 20:43:26) Copyright (c) 1997-2006 The PHP Group Zend Engine v2.2.0, Copyright (c) 1998-2006 Zend Technologies