fixedpoint.jp


Scheme の min / max にまつわる問題 (2014-10-31)

Scheme には minmax という1つ以上の real number の最小値および最大値を返す手続きがあります。R5RS から R7RS に至るまで、その numerical tower に沿って一貫して定義されています。(ただし R6RS では positive infinity と negative infinity についての記述が追加されていました。)

ところが上の定義には問題があります。引数によっては最小値や最大値が定義できない場合があるのです。「引数の集合は有限個の実数の集合なんだから、常に最小値と最大値が存在するだろう」というのは数学的に正しいですが、Scheme の場合 NaN が real number に含まれています。NaN は(NaN 自身を含め)どの real number と比較した場合でも false (#f)になるとされているため、NaN が引数に出てくると total order になりません。

このことが関係して、minmax に NaN を渡すと一見奇妙な振舞いをする実装もあります。例えば GaucheYpsilon は引数の順序によって返る値が変わります:

$ gosh -V
Gauche scheme shell, version 0.9.4 [utf-8,pthreads], x86_64-unknown-linux-gnu
$ gosh
gosh> (min +nan.0 1)
+nan.0
gosh> (min 1 +nan.0)
1.0
gosh> (max +nan.0 1)
+nan.0
gosh> (max 1 +nan.0)
1.0
gosh> 
$ ypsilon
Ypsilon 0.9.6-update3 Copyright (c) 2008 Y.Fujita, LittleWing Company Limited.
> (min +nan.0 1)
1.0
> (min 1 +nan.0)
+nan.0
> (max +nan.0 1)
+nan.0
> (max 1 +nan.0)
1.0
> 
これらは「引数のうち極小値(または極大値)のいずれかを返す」ものと解釈することができます。一方 Racket の場合は、用意周到に「NaN が引数に出てきた場合には NaN を返す」とドキュメンテーションに書かれています: http://docs.racket-lang.org/reference/generic-numbers.html

ちなみに R5RS/R7RS では NaN や infinity は実装拡張とされ、NaN がサポートされていない実装では問題ありません。

参考:


© 2006-2023 fixedpoint.jp