You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@couchdb.apache.org by Michael Franzkowiak <mi...@franzkowiak.org> on 2009/12/12 13:33:28 UTC

sum function in reduce with precision problems?

Hi,

I just recently started to look at couchdb but I already love so many aspects of it.

One thing that really worries me though is something I encountered today:

CouchDB seems to think that 0.79 + 5.99 + 1.59 = 8.370000000000001

This is the only document I have in my database:
{
   "_id": "xyz",
   "_rev": "...",
   "item": "BMW 320d",
   "prices": {
       "Base Price": 1.59,
       "Extra 1": 5.99,
       "Extra 2": 0.79
   }
}

This is my map / reduce function:

function(doc) {
  var p;
    
  for (p in doc.prices) {
       emit(doc.item, doc.prices[p])
  }

}

function(keys, values){
 return sum(values);
}

Calling with group=true this results in 
{"rows":[
{"key":"BMW 320d","value":8.370000000000001}
]}
I could always just multiply my numbers with the precision I need and work with ints but I'm still curious to see this explained.
Michael 

Re: sum function in reduce with precision problems?

Posted by Metin Akat <ak...@gmail.com>.
I am writing financial software with CouchDB backend.
So far the best solution for me is to use rationals for arithmetic.
In order to achieve this I use couchdb-python view server. I store
rationals as strings in the database, for example "1/2", "3/4" etc.
Then I use Python's fractions module to convert them to rationals and
do arithmetic with them. It's easy like a piece of cake:

>>> from fractions import Fraction as F
>>> F('1/2') + F('3/4')
Fraction(5, 4)


The "store cents" method works for simpler tasks, but if you need to
have things like different currencies it becomes a nightmare.

I am very much interested to find out if someone knows better solution
(one that could fit in the standard javascript view server), but so
far I don't think that there is such. And my solution seems to work
fine for now.

Re: sum function in reduce with precision problems?

Posted by Nicholas Orr <ni...@zxgen.net>.
Yeah I've picked this route - it is a bit of a pain though that map/reduce
can't make use of the data and need process app/client side. Just lucky in
this particular app it is really a moot point and the diff in speed is for
intents zero.

Nick

2009/12/13 Brian Candler <B....@pobox.com>

> On Sat, Dec 12, 2009 at 01:18:41PM +0000, Leo Simons wrote:
> > Looks like you're representing money; just work with cents (stored as
> > ints) and you will *probably* be fine, especially if you stay clear of
> > divisions. I wouldn't try and implement my own finance package that way,
> > though :)
> >
> > Alternatively, implement your own decimal type in javascript, or use a
> > relational database :)
>
> Or store strings (and deal with them with your client's BigDecimal or
> equivalent)
>

Re: sum function in reduce with precision problems?

Posted by Brian Candler <B....@pobox.com>.
On Sat, Dec 12, 2009 at 01:18:41PM +0000, Leo Simons wrote:
> Looks like you're representing money; just work with cents (stored as  
> ints) and you will *probably* be fine, especially if you stay clear of  
> divisions. I wouldn't try and implement my own finance package that way,  
> though :)
>
> Alternatively, implement your own decimal type in javascript, or use a  
> relational database :)

Or store strings (and deal with them with your client's BigDecimal or
equivalent)

Re: sum function in reduce with precision problems?

Posted by Matteo Caprari <ma...@gmail.com>.
I'm writing a finance app and was looking for solutions to the
precision problem.

I found some stuff. I have not tested any of it as at first glance
this all thing feels overkill. There may be a more elegant solution.

bigdecimal.js part of gwt-math
http://code.google.com/p/gwt-math/source/browse/trunk/gwt-math/js_originals/bigdecimal.js

BigDecimal support for JavaScript
http://stz-ida.de/html/oss/js_bigdecimal.html.en

Big Number
http://jsfromhell.com/classes/bignumber

On Sat, Dec 12, 2009 at 1:18 PM, Leo Simons <ma...@leosimons.com> wrote:
> On 12/12/09 12:33 PM, Michael Franzkowiak wrote:
>>
>> CouchDB seems to think that 0.79 + 5.99 + 1.59 = 8.370000000000001
>
> So does most other software when using floating point arithmetic:
>
> $ python -c 'print "%.15f" % (0.79 + 5.99 + 1.59)'
> 8.370000000000001
> $ perl -e 'print sprintf("%.15f\n", 0.79 + 5.99 + 1.59);'
> 8.370000000000001
> $ python -c 'print "%.20f" % (0.79 + 5.99 + 1.59)'
> 8.37000000000000099476
> $ perl -e 'print sprintf("%.20f\n", 0.79 + 5.99 + 1.59);'
> 8.37000000000000099476
>
> This is standard stuff (
> http://docs.sun.com/source/806-3568/ncg_goldberg.html ).
>
>> I could always just multiply my numbers with the precision I need
>
>> and work with ints but I'm still curious to see this explained.
>
> What you really really want is a decimal type:
>
> $ python -c 'from decimal import Decimal; print Decimal("0.79") +
> Decimal("5.99") + Decimal("1.59")'
> 8.37
>
> ...but there is no decimal type in javascript or json so also does not exist
> in CouchDB.
>
> Looks like you're representing money; just work with cents (stored as ints)
> and you will *probably* be fine, especially if you stay clear of divisions.
> I wouldn't try and implement my own finance package that way, though :)
>
> Alternatively, implement your own decimal type in javascript, or use a
> relational database :)
>
> ciao,
>
> Leo
>



-- 
:Matteo Caprari
matteo.caprari@gmail.com

Re: sum function in reduce with precision problems?

Posted by Leo Simons <ma...@leosimons.com>.
On 12/12/09 12:33 PM, Michael Franzkowiak wrote:
> CouchDB seems to think that 0.79 + 5.99 + 1.59 = 8.370000000000001

So does most other software when using floating point arithmetic:

$ python -c 'print "%.15f" % (0.79 + 5.99 + 1.59)'
8.370000000000001
$ perl -e 'print sprintf("%.15f\n", 0.79 + 5.99 + 1.59);'
8.370000000000001
$ python -c 'print "%.20f" % (0.79 + 5.99 + 1.59)'
8.37000000000000099476
$ perl -e 'print sprintf("%.20f\n", 0.79 + 5.99 + 1.59);'
8.37000000000000099476

This is standard stuff ( 
http://docs.sun.com/source/806-3568/ncg_goldberg.html ).

> I could always just multiply my numbers with the precision I need
 > and work with ints but I'm still curious to see this explained.

What you really really want is a decimal type:

$ python -c 'from decimal import Decimal; print Decimal("0.79") + 
Decimal("5.99") + Decimal("1.59")'
8.37

...but there is no decimal type in javascript or json so also does not 
exist in CouchDB.

Looks like you're representing money; just work with cents (stored as 
ints) and you will *probably* be fine, especially if you stay clear of 
divisions. I wouldn't try and implement my own finance package that way, 
though :)

Alternatively, implement your own decimal type in javascript, or use a 
relational database :)

ciao,

Leo