Modifying the value of a float-like object

Dave Angel davea at ieee.org
Wed Apr 15 05:31:05 EDT 2009


Eric.Le.Bigot at 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... at ieee.org> wrote:
>   
>> Eric.Le.Bi... at 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... at 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





More information about the Python-list mailing list