Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Significant figures calculation

Reply
Thread Tools

Significant figures calculation

 
 
Harold
Guest
Posts: n/a
 
      06-24-2011
Hi,

I am looking for an easy way to do significant figure calculations in
python (which I want to use with a class that does unit calculations).
Significant figure calculations should have the semantics explained,
e.g., here: http://chemistry.about.com/od/mathsc...sigfigures.htm

My hope was that the decimal module would provide this functionality,
but:

>>> print Decimal('32.01') + Decimal(5.325) + Decimal('12')

49.335 # instead of 49
>>> print Decimal('25.624') / Decimal('25')

1.02496 # instead of 1.0
>>> print Decimal('1.2') == Decimal('1.23')

False # actually not sure how the semantics should be

I tried to modify the DecimalContext (e.g. getcontext().prec = 2) but
that did not lead to the correct behavior. Google and this list didn't
yield a good answer yet... so I'd be happy to get a good
recommendations or pointers.

P.S. I am aware that significant figure calculation is controversial
and makes implicit assumptions on the probability distributions of the
variables. I am simply looking for an implementation of the (well
defined) arithmetics as defined on the cited website.
 
Reply With Quote
 
 
 
 
Steven D'Aprano
Guest
Posts: n/a
 
      06-24-2011
On Fri, 24 Jun 2011 13:05:41 -0700, Harold wrote:

> Hi,
>
> I am looking for an easy way to do significant figure calculations in
> python (which I want to use with a class that does unit calculations).
> Significant figure calculations should have the semantics explained,
> e.g., here:
> http://chemistry.about.com/od/mathsc...sigfigures.htm
>
> My hope was that the decimal module would provide this functionality,
> but:
>
>>>> print Decimal('32.01') + Decimal(5.325) + Decimal('12')

> 49.335 # instead of 49
>>>> print Decimal('25.624') / Decimal('25')

> 1.02496 # instead of 1.0
>>>> print Decimal('1.2') == Decimal('1.23')

> False # actually not sure how the semantics should be
>
> I tried to modify the DecimalContext (e.g. getcontext().prec = 2) but
> that did not lead to the correct behavior.


Really? It works for me.


>>> import decimal
>>> D = decimal.Decimal
>>> decimal.getcontext().prec = 2
>>>
>>> D('32.01') + D('5.325') + D('12')

Decimal('49')
>>>
>>> D('25.624') / D('25')

Decimal('1.0')

The only thing you have to watch out for is this:

>>> D('1.2') == D('1.23') # no rounding

False
>>> D('1.2') == +D('1.23') # force rounding

True



--
Steven
 
Reply With Quote
 
 
 
 
Jerry Hill
Guest
Posts: n/a
 
      06-24-2011
On Fri, Jun 24, 2011 at 4:46 PM, Steven D'Aprano
<(E-Mail Removed)> wrote:
> Really? It works for me.
>
>>>> import decimal
>>>> D = decimal.Decimal
>>>> decimal.getcontext().prec = 2
>>>>
>>>> D('32.01') + D('5.325') + D('12')

> Decimal('49')


I'm curious. Is there a way to get the number of significant digits
for a particular Decimal instance? I spent a few minutes browsing
through the docs, and didn't see anything obvious. I was thinking
about setting the precision dynamically within a function, based on
the significance of the inputs.

--
Jerry
 
Reply With Quote
 
steve+comp.lang.python@pearwood.info
Guest
Posts: n/a
 
      06-25-2011
Jerry Hill wrote:

> I'm curious. Is there a way to get the number of significant digits
> for a particular Decimal instance? I spent a few minutes browsing
> through the docs, and didn't see anything obvious. I was thinking
> about setting the precision dynamically within a function, based on
> the significance of the inputs.


Not officially, so far as I know, but if you're willing to risk using a
private implementation detail that is subject to change:

>>> decimal.Decimal('000123.45000')._int

'12345000'

However, sometimes you may need to inspect the exponent as well:

>>> zero = decimal.Decimal('0.00000000')
>>> zero._int

'0'
>>> zero._exp

-8



--
Steven

 
Reply With Quote
 
Harold
Guest
Posts: n/a
 
      06-25-2011
> > I tried to modify the DecimalContext (e.g. getcontext().prec = 2) but
> > that did not lead to the correct behavior.

>
> Really? It works for me.


You are right, I did something wrong when attempting to set the
precision.
And the trick with rounding the decimal with the unary + is neat.
It's the first time for me to play with decimals, so bare with me if I
miss
the obvious.

However, this approach forces you to know the number of significant
figures
beforehand -- which is precisely what the arithmetics should do for
you.
What would indeed be nice, is Jerry's suggestion to obtain the number
of
significant bits and write a small wrapper around the number protocoll
implementation that accounts significance and have __str__/__repr__
set
the context dynamically.

I haven't seen anything obvious in the docs, though it might be
possible
to use log10 of the length of some normalized string representation.
 
Reply With Quote
 
Chris Torek
Guest
Posts: n/a
 
      06-25-2011
In article <(E-Mail Removed)>
Jerry Hill <(E-Mail Removed)> wrote:
>I'm curious. Is there a way to get the number of significant digits
>for a particular Decimal instance?


Yes:

def sigdig(x):
"return the number of significant digits in x"
return len(x.as_tuple()[1])

import decimal
D = decimal.Decimal

for x in (
'1',
'1.00',
'1.23400e-8',
'0.003'
):
print 'sigdig(%s): %d' % (x, sigdig(D(x)))
--
In-Real-Life: Chris Torek, Wind River Systems
Intel require I note that my opinions are not those of WRS or Intel
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html
 
Reply With Quote
 
Harold
Guest
Posts: n/a
 
      06-26-2011
> >I'm curious. *Is there a way to get the number of significant digits
> >for a particular Decimal instance?

>
> Yes:
>
> def sigdig(x):
> * * "return the number of significant digits in x"
> * * return len(x.as_tuple()[1])


Great! that's exactly what I needed.
thanks Chris!
 
Reply With Quote
 
Dave Angel
Guest
Posts: n/a
 
      06-27-2011
(You top-posted your reply, instead of writing your response following
the part you were quoting)

On 01/-10/-28163 02:59 PM, Lalitha Prasad K wrote:
> In numerical analysis there is this concept of machine zero, which is
> computed like this:
>
> e=1.0
> while 1.0+e> 1.0:
> e=e/2.0
> print e
>
> The number e will give you the precision of floating point numbers.
>
> Lalitha Prasad
>


That particular algorithm is designed for binary floating point. The OP
was asking about Decimal instances. So you'd want to divide by 10.0
each time. And of course you'd want to do it with Decimal objects.
> On Sun, Jun 26, 2011 at 9:05 PM, Harold<(E-Mail Removed)> wrote:
>
>>>> I'm curious. Is there a way to get the number of significant digits
>>>> for a particular Decimal instance?


DaveA

 
Reply With Quote
 
Harold
Guest
Posts: n/a
 
      06-27-2011
On Jun 25, 9:04*pm, Chris Torek <(E-Mail Removed)> wrote:
> >I'm curious. *Is there a way to get the number of significant digits
> >for a particular Decimal instance?

>
> Yes:
>
> def sigdig(x):
> * * "return the number of significant digits in x"
> * * return len(x.as_tuple()[1])


Great, Chris, this is (almost) exactly what I needed.
To make it work for numbers like 1200, that have four digits but only
two of them being significant, I changed your snippet to the
following:

class Empirical(Decimal) :
@property
def significance(self) :
t = self.as_tuple()
if t[2] < 0 :
return len(t[1])
else :
return len(''.join(map(str,t[1])).rstrip('0'))


>>> Empirical('1200.').significance

2
>>> Empirical('1200.0').significance

5

now it's only about overriding the numerical operators
 
Reply With Quote
 
Ethan Furman
Guest
Posts: n/a
 
      06-27-2011
Harold wrote:
> On Jun 25, 9:04 pm, Chris Torek <(E-Mail Removed)> wrote:
>>> I'm curious. Is there a way to get the number of significant digits
>>> for a particular Decimal instance?

>> Yes:
>>
>> def sigdig(x):
>> "return the number of significant digits in x"
>> return len(x.as_tuple()[1])

>
> Great, Chris, this is (almost) exactly what I needed.
> To make it work for numbers like 1200, that have four digits but only
> two of them being significant, I changed your snippet to the
> following:
>
> class Empirical(Decimal) :
> @property
> def significance(self) :
> t = self.as_tuple()
> if t[2] < 0 :
> return len(t[1])
> else :
> return len(''.join(map(str,t[1])).rstrip('0'))
>
>
>>>> Empirical('1200.').significance

> 2
>>>> Empirical('1200.0').significance

> 5


What about when 1200 is actually 4 significant digits? Or 3?

~Ethan~
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Rounding any number (int or float) to 3 significant figures Max Williams Ruby 6 05-16-2009 01:25 PM
Significant Digits (Significant Figures) SMH Javascript 0 01-07-2007 09:52 AM
Re: Round to significant figures (C++) Alf P. Steinbach C++ 0 05-01-2006 09:15 AM
more than 16 significant figures Jeremy Watts Java 32 07-15-2005 02:21 PM
round up to nearest number and significant figures Steve Java 5 05-17-2004 01:30 AM



Advertisments