eric.le.bi...@spectro.jussieu.fr wrote:
Thanks Dave for your thoughtful remarks, which you sent right when I
was writing a response to the previous posts.

I was wondering about a kind "mutable float"; so you're right, it's
not fully a float, because it's mutable.  I'd like to have an object
that behaves like a float in numerical calculations.  I understand
that mutability would require to handle such objects with care, as in
your example, but Python programmers are used to this with any mutable
object.  All my calculations use "constants with an uncertainty" (or
regular floats).

There are many such calculations in my code, and I'd like it to be
very clean.  The first idea I mentioned (using "x()") is essentially
what you propose with using "x[0]" in calculations.

So, it looks like it's not possible to have float-like objects
(calculation/formula-wise) that are mutable?!  and it also looks like
the price to pay for the mutability is to have to write "heavier"
versions of any formula that uses these "special floats" (that carry
an uncertainty): "x[0]+y[0]*sin(...)", "x()+y()", "float(x)+float
(y)",...  which, by the way, essentially prevents any float-like
object from being used as a float in formulas that you don't write
yourself.

This does not look good.  Python is failing me!!! :/  I heard that
this would be easy to do in Ruby (not confirmed, though)...

More ideas and thoughts would still be most welcome!

On Apr 14, 8:45 pm, Dave Angel <da...@ieee.org> wrote:
eric.le.bi...@spectro.jussieu.fr wrote:
It looks like what is needed here are a kind of "mutable float".  Is
there a simple way of creating such a type?  I don't mind changing the
value through x.value =3 instead of x = 1.23... :)
On Apr 14, 3:03 pm, eric.le.bi...@spectro.jussieu.fr wrote:
Hello,
Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed?  The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value =4) so that any expression like "x
+y" uses the new value.
I thought of two solutions, both of which I can't make to work: 1) Use a class that inherits from float. This takes care of the
"behave like float" part.  But is it possible to change the value of
the float associated with an instance?  That is, is it possible to
do:  "x =loat(1.23); x.change_value(3.14)" so that x's float value
becomes 3.14?
2) The other possibility I thought of was: use a class that defines a
'value' member (x.value).  This takes care of the "value can be
changed" part.  But is it possible/easy to make it fully behave like a
float (including when passed to functions like math.sin)?
Alternatively, I'd be happy with a way of handling numerical
uncertainties in Python calculations (such as in "calculate the value
and uncertainty of a*sin(b) knowing that a=+/- 0.1 and b=1.00 +/-
0.01").
Any idea would be much appreciated!
The answer to your original question is no.  If the value can be changed, then 
it doesn't behave like a float.  And that's not just a pedantic answer, it's a 
serious consideration.

You have to decide what characteristics of a float you need to mimic, and which ones you 
don't care about, and which ones you want to change.  Only after having a pretty good 
handle on those answers can you pick a "best" implementation.

Let's call this new type a nfloat, and let's assume you have a function that 
returns one.  That might be a constructor, but it may not, so we're keeping our 
options open.
  myval =ewfunction(42.0)

What do you want to happen when you execute   b =yval ?   Presumably
you want them to be "equal" but in what sense?  Suppose you then change
one of them with your suggested attribute/method.
     myval.value =ewfunction("aaa")

is b the same as it was (like a float would be), or is b also changed?

Do you need lots of functions to work on one of these nfloats, or could
you use them as follows:
     sin( b.value )

Instead of using .value to change the underlying float, how about if you
use [0] ?  Just use a list of size 1.


OK, your other recent message clarified for me some of what you're after. Seems to me you're going to have a specific list of values, which you want to be able to individually tweak each time you do the calculations. And you want to have a name for each of those values, so that the formulas look pretty straightforward.

I'm not convinced this is the best approach for uncertainty calculations, but if those numbers do form a fairly easily specified list (and one that's not dynamic), what you probably want is an object that's a reference to a list item, while the list item is itself a float. And you want the object to support many of the usual floating point operations. So why not define a single static list (could be a class object), and define a class whose instances contain an index into that list. The class could have methods __add__() and __mul__() etc. And it could have one more method for storing to the list.


class IndirectFloat(object):
liss = []
def __init__(self, value=0.0):
self.index = len(self.liss)
self.liss.append(value)

def modify(self, newvalue):
self.liss[self.index]= newvalue

def __add__(self, val): #handle IndirectFloat + float
return self.liss[self.index] + float(val)

__radd__ = __add__ #handle float + IndirectFloat

def __float__(self): #just in case someone wants to explicitly convert
return self.liss[self.index]

x = IndirectFloat(12.0)
y = IndirectFloat(20.0)
print x + 13.0
print x + y
print 3.0 + x
x.modify(15.0)
print x + 13.0

Notice that if you ever do things like z = y, you'll be using the *same* object, and modifying one will also modify the other. Now, in addition to __add__ and __radd__, you want __mul__ and __rmul__, and many others, presumably. Notice that for the non-commutative methods, you can't just use the same method for both, the way we do for add and multiply.

I still think an error-propagation class would be better.
Something like:
class ErrorPropFloat(object):
def __init__(self, value=0.0, err=0.0):
self.value = value
self.err = err

def __add__(self, val):
res = self.value + float(val)
if type(val) == type(0.0):
err = self.err
else:
err = self.err + val.err
return ErrorPropFloat(res, err)

__radd__ = __add__

def __float__(self): #just in case someone wants to explicitly convert
return self.value
def __repr__(self):
return "ErrorProp(%g, %g)" % (self.value, self.err)
#return "ErrorProp(" + self.value + "," + self.err + ")"

x = ErrorPropFloat(12.0, 0.1)
y = ErrorPropFloat(20.0, 0.2)
print x, y
print x + 13.0
print x + y
print 3.0 + x


--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to