n == n + 1

ときどきの雑記帖経由、2007-11-25 - プログラミング日記

Pythonクイズ。以下を満たすnの値は何でしょうか?

>>> n = ???
>>> n == n + 1
True


30秒ほど考えて、たぶん浮動小数点だよなあと思って、

>>> 1e20 == 1e20 + 1
True
>>> 1e15 == 1e15 + 1
False
>>> 1e16 == 1e16 + 1
True
>>> 

やっぱり。せっかくだから別の言語でもやってみる。

Cで

#include <stdio.h>

#ifndef N
#define N 1e20
#endif

int main(int argc, char *argv[]) {
#ifdef USE_DOUBLE
    double n = N;
#else
    float n = N;
#endif
    printf("n = %f\n", n);
    printf("n == n + 1 ? %c\n", "FT"[n == n + 1]);
    return 0;
}
$ gcc -Wall main.c
$ ./a.out 
n = 100000002004087734272.000000
n == n + 1 ? T
$ gcc -Wall -DUSE_DOUBLE main.c
$ ./a.out 
n = 100000000000000000000.000000
n == n + 1 ? T
$ gcc -Wall -DN=1e19 main.c
$ ./a.out 
n = 9999999980506447872.000000
n == n + 1 ? F
$ gcc -Wall -DN=1e19 -DUSE_DOUBLE main.c
$ ./a.out 
n = 10000000000000000000.000000
n == n + 1 ? F

Cだと1e19と1e20の間に限界があるようだ。floatでもdoubleでも同じ結果なのは面白い。(もしかしたら何かミスってるかも)

Perl

$ perl -e 'printf "%s\n", [qw(False True)]->[1e15 == 1e15 + 1]'
False
$ perl -e 'printf "%s\n", [qw(False True)]->[1e16 == 1e16 + 1]'
True

PerlPythonと同じみたい。

Scheme

gosh> (= 1e16 (+ 1e16 1))
#t
gosh> (= 1e15 (+ 1e15 1))
#f

Gaucheでも同じ。

Java

public class Main {
    public static void main(String[] args) {
        double n = args.length > 0 ?  Double.parseDouble(args[0]) : 1e16;
        System.out.println(n == n + 1);
    }
}
$ javac Main.java 
$ java Main 1e15
false
$ java Main 1e16
true

Javaも同じだ。

Javascript

もう結果は見えてる気もするけどやってみると、

$ telnet localhost 4242
repl> 1e15 == 1e15 + 1
false
repl> 1e16 == 1e16 + 1
true

やっぱりJavascriptも同じ。
ちなみに、Javascriptインタラクティブに評価するためにMozReplを使ってます。

再びPython

実はPythonだと別解もあって、

>>> class C(object):
...     def __add__(self, other):
...         return self
... 
>>> o=C()
>>> o+1
<__main__.C object at 0xb7ed022c>
>>> o == o+1
True

ユーザ定義型も使ってよければこんなのでもいい。
同様のアプローチは演算子オーバーロードのできる言語(C++とか)なら可能だと思う。