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