2013-02-23 1 views
2
Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26). 

scala> 1.0/Double.MinPositiveValue 
res0: Double = Infinity 

Ох. Раздражает. Я надеялся, что я мог бы сделать что-то вроде:Как я могу найти самый маленький делитель `Double`, который не даст бесконечного результата?

def f(x: Double) = 1.0/(x + Double.MinPositiveValue) 

... и избежать Infinity для f(0.0). Попробуем найти несколько большее число:

scala> val xs = Iterator.iterate(Double.MinPositiveValue)(_ + Double.MinPositiveValue) 
xs: Iterator[Double] = non-empty iterator 

scala> xs.take(10).toList 
res1: List[Double] = List(4.9E-324, 1.0E-323, 1.5E-323, 2.0E-323, 2.5E-323, 3.0E-323, 3.5E-323, 4.0E-323, 4.4E-323, 4.9E-323) 

ОК. Хорошо. Он растет. Как насчет:

scala> xs.map(1.0/_).take(10).toList 
res2: List[Double] = List(Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity) 

Хм ... может быть, это займет какое-то время. Давайте попробуем:

scala> xs.find(x => !(1.0/x).isInfinite) 

... и я все еще жду этого. Не похоже, что он скоро закончится.

Как найти самый маленький Double делитель, который не даст бесконечного результата?

+0

После небольшого проб и ошибок, я почти уверен, что номер '5.56268464626801E-309'. –

+0

Почему вы ищете этот волшебный номер? –

+0

@ RandallSchulz См. Мое определение 'f'. Немного больше контекста: я взвешиваю вещи, обращая их расстояние до какой-то другой вещи. Если это расстояние равно нулю, я хочу очень большой вес, но не бесконечный ... –

ответ

3

Если вы собираетесь искать, по крайней мере, искать с делением пополам, которое должно занимать не более 1024 итераций, так как это 2 (#bits in exponent).

Но, оказывается, вам не нужно, потому что вы можете найти его с помощью пробной версии еще быстрее. Это должно быть очень близко к 1/Double.MaxValue:

scala> Double.MaxValue 
res35: Double = 1.7976931348623157E308 

scala> 1/res35 
res36: Double = 5.562684646268003E-309 

scala> 1/res36 
res37: Double = Infinity 

scala> 1/(res36+math.ulp(res36)) 
res38: Double = 1.7976931348623143E308 

scala> res36+math.ulp(res36) 
res39: Double = 5.56268464626801E-309 

Не так уж плохо.

+0

Я немного обеспокоен тем, что '1/(1/Double.MaxValue) == Double.MaxValue' является' false '. Но я думаю, что это операция с плавающей запятой. –