2015-12-23 2 views
0

Я столкнулся с странной проблемой при попытке суммировать список удвоений, которые содержатся в разных экземплярах, используя foldLeft. При расследовании кажется, что даже при работе со списком простых удвоений проблема не устраняется:foldLeft в списке Doubles возвращает странное значение

val listOfDoubles = List(4.0, 100.0, 1.0, 0.6, 8.58, 80.0, 22.33, 179.99, 8.3, 59.0, 0.6) 
listOfDoubles.foldLeft(0.0) ((elem, res) => res + elem) // gives 464.40000000000003 instead of 464.40 

Что я здесь делаю неправильно?

Примечание:foldLeft здесь необходимы, так как то, что я пытаюсь достичь, это сумма удваивается, содержащаяся в различных экземплярах case class SomeClass(value: Double), если, конечно, не существует другой способ пойти об этом.

ответ

3

Что я здесь делаю неправильно?

Использование удваивается, когда вам нужна эта точность. Это не проблема с foldLeft. Вы страдаете от ошибки округления с плавающей запятой. Проблема в том, что некоторые числа нуждаются в очень длинных (или бесконечных) представлениях в двоичном виде, а это означает, что их нужно усечь в двоичной форме. И при преобразовании обратно в десятичную, это двоичные ошибки округления поверхностей.

Вместо этого используется BigDecimal, так как он предназначен для произвольной точности.

scala> val list: List[BigDecimal] = List(4.0, 100.0, 1.0, 0.6, 8.58, 80.0, 22.33, 179.99, 8.3, 59.0, 0.6) 
list: List[BigDecimal] = List(4.0, 100.0, 1.0, 0.6, 8.58, 80.0, 22.33, 179.99, 8.3, 59.0, 0.6) 

scala> list.foldLeft(BigDecimal(0.0))(_ + _) 
res3: scala.math.BigDecimal = 464.40 

Или просто:

scala> list.sum 
res4: BigDecimal = 464.40 
+1

http://stackoverflow.com/questions/2100490/floating-point-inaccuracy-examples –

+1

http://0.30000000000000004.com/ имеет большое объяснение из первопричиной этого (с несколькими примерами в Scala) – Hamish

Смежные вопросы