[Tutor] class uncertainty
Hans Nowak
hnowak@cuci.nl
Tue, 28 Aug 2001 09:47:18 +0200
>===== Original Message From "Christopher Smith" <csmith@blakeschool.org>
=====
>I've created a class which keeps track of the uncertainty in a number and
>subsequent calculations performed with that number. It works like this:
>
>u=uncertainty #shorten the name
>
># define physical measurements
># with +/-1 in last digit by default
>p=u('1.0')
>R=u('.0821')
>T=u('298')
>
># define a physical measurement witha larger uncertainty
>n=u('1.0,.15')
>
>#do the calculation and look at results
>v=n*R*T/p
>print v
>print v[0]
>print v[1]
>
>#results are
># 24 +/- 9
># 24.4658
># 9.31980083228
Looks neat... why is u() taking strings, though?
>I am in need of some advice now regarding two things:
>
>1) I want to be able to use the math functions on the class.
>Should I do this as methods, e.g. x.log(), or should I redefine
>the math functions so that when the module is loaded you now have
>
>def log(x):
> if type(x)==<the type of my class>:
> return uncertain.log(x)
> return math.log(x)
>
>I would prefer the latter so the operation is as seamless as possible.
>That's where I need the advise, though.
Redefining existing functions is usually a bad idea, but in this case you're
preserving the original behavior of math.log for objects other than your
class, so I guess it's not as bad. This is more of a design question than
anything else... will the users of your class expect methods or functions?
This may be simplified to: are they coming from an OO background, or a
functional programming one? I don't think there's much to say to give one a
significant benefit over the other, except maybe that <your_class>.log() would
be less ambiguous than using a log function.
There's another possibility, though... I don't know if this makes sense for
your class, but you can define the __float__ method, and have it return the
float value you're trying to take the log() of. A trivial example:
>>> class Foo:
def __init__(self, x):
self.x = x
def __float__(self):
try:
return float(self.x)
except:
return 1.0
>>> f = Foo(99)
>>> math.log(f)
4.5951198501345898
>>> g = Foo("bla")
>>> math.log(g)
0.0
I haven't tested this thoroughly, but I think it might be a solution for your
problem.
>2) Along the same lines, I would prefer not to have to explicitly create
>my class. Is there a way to overload the "=" like the algebraic operators?
Nope. :)
>Once you load the class it would treat all numbers as strings and make them
>into class instances unless, for example, they were followed by 'x' which
>would denote 'exact'. My guess this is not the way to go.
>
>Would another approach be to write an evaluator which would work like this:
>
>####
>#put the whole 'calculation in triple quotes
>res=uevaluate('''
>p=1.0
>R=0.0821
>T=298.15
>n=1.0,.15
>
>v=n*R*T/p
>print v
>
>in=3.0
>print in*2.54x #the x denotes an exact value
>'''
># and now see the results
>for ri in res:
> print ri
>
>24 +/- 9
>7.6 +/- 0.3
>####
Ouch... this last approach would require you to parse the code, find all (?)
numbers, and replace them with u() instances. I think your original approach
was just fine... at least people reading the code would know you are dealing
with uncertainty objects. This is better than implicit conversions, IMHO.
HTH,
--Hans Nowak