I'm starting with a pure python implementation and have some progress. AFAICT, the only approach is to subclass ndarray and add the properties and behaviors I need. I ran into one issue though. In my function 'as_double', I need to get to the underlying 'int' array to pass to ldexp. I tried using view, but it silently fails: In [40]: obj Out[40]: fixed_pt_array([ 0, 32, 64, 96, 128]) In [41]: obj.view (int) Out[41]: fixed_pt_array([ 0, 32, 64, 96, 128]) How can I get at the underlying int array to pass to ldexp? Here is the prototype code (far from complete!) import numpy as np def rnd (x, frac_bits, _max): x1 = x >> (frac_bits-1) if (x1 == _max): return x1 >> 1 else: return (x1+1) >> 1 def shift_left (x, bits): return x << bits def shift_right (x, bits): return x >> bits def shiftup_or_rnddn (x, bits, _max, rnd_policy): if (bits > 0): return shift_left (x, bits) elif (bits < 0): return rnd_policy (x, -bits, _max) else: return x def clip (x, _min, _max): if x > _max: return _max elif x < _min: return _min else: return x class fixed_pt (object): def get_max(self): if self.is_signed: return (~(self.base_type(-1) << (self.total_bits-1))) else: return (~(self.base_type (-1) << self.total_bits)) def get_min(self): if self.is_signed: return ((self.base_type(-1) << (self.total_bits-1))) else: return 0 def __init__ (self, int_bits, frac_bits, val, scale=True, base_type=int, rnd_policy=rnd, overflow_policy=clip, is_signed=True): self.is_signed = is_signed self.int_bits = int_bits self.frac_bits = frac_bits self.base_type = base_type self.total_bits = int_bits + frac_bits self.rnd_policy = rnd_policy self._max = self.get_max () self._min = self.get_min () self.overflow_policy = overflow_policy if scale: self.val = self.overflow_policy (self.base_type (shiftup_or_rnddn (val, frac_bits, self._max, self.rnd_policy)), self._min, self._max) def as_double (self): return np.ldexp (self.val, -self.frac_bits) def as_base (self): return shiftup_or_rnddn (self.val, -self.frac_bits, self._max, self.rnd_policy) def __repr__(self): return "[%s <%s,%s>]" % (self.val, self.int_bits, self.frac_bits) def get_max(is_signed, base_type, total_bits): if is_signed: return (~(base_type(-1) << (total_bits-1))) else: return (~(base_type (-1) << total_bits)) def get_min(is_signed, base_type, total_bits): if is_signed: return ((base_type(-1) << (total_bits-1))) else: return 0 class fixed_pt_array(np.ndarray): def __new__(cls, input_array, int_bits, frac_bits, scale=True, base_type=int, rnd_policy=rnd, overflow_policy=clip, is_signed=True): # Input array is an already formed ndarray instance # We first cast to be our class type obj = np.asarray(input_array, dtype=base_type).view(cls) # add the new attribute to the created instance obj.int_bits = int_bits obj.frac_bits = frac_bits obj.rnd_policy = rnd_policy obj.overflow_policy = overflow_policy obj.is_signed = is_signed obj.scale = scale obj.base_type = base_type obj.total_bits = int_bits + frac_bits obj._max = get_max(is_signed, base_type, obj.total_bits) obj._min = get_min(is_signed, base_type, obj.total_bits) if scale: def _scale (val): return overflow_policy (base_type (shiftup_or_rnddn (val, frac_bits, obj._max, rnd_policy)), obj._min, obj._max) vecfunc = np.vectorize (_scale) obj = vecfunc (obj) # Finally, we must return the newly created object: return obj def __array_finalize__(self,obj): # reset the attribute from passed original object if hasattr (obj, 'int_bits'): self.int_bits = obj.int_bits self.frac_bits = obj.frac_bits self.is_signed = obj.is_signed self.base_type = obj.base_type self.total_bits = obj.total_bits self._max = obj._max self._min = obj._min ## self._max = get_max(self.is_signed, self.base_type, self.total_bits) ## self._min = get_min(self.is_signed, self.base_type, self.total_bits) # We do not need to return anything ## def __getitem__ (self, index): ## return fp.fixed_pt_int64_clip (self.int_bits, self.frac_bits, int(np.ndarray.__getitem__(self, index))) def as_double (self): def _as_double (x): print type(x) return np.ldexp (x, -self.frac_bits) return _as_double (self.view (self.base_type)) fp = fixed_pt (5, 5, 1) arr = np.arange(5,dtype=int) obj = fixed_pt_array(arr, int_bits=5, frac_bits=5) print type(obj)
This doesn't work either: def as_double (self): import math def _as_double_1 (x): return math.ldexp (x, -self.frac_bits) vecfunc = np.vectorize (_as_double_1, otypes=[np.float]) return vecfunc (self) In [49]: obj.as_double() Out[49]: fixed_pt_array([ 0., 1., 2., 3., 4.]) The values are correct, but I wanted a float array, not fixed_pt_array for output.
On Tue, Sep 29, 2009 at 10:22 AM, Neal Becker <ndbecker2@gmail.com> wrote:
This doesn't work either:
def as_double (self): import math def _as_double_1 (x): return math.ldexp (x, -self.frac_bits) vecfunc = np.vectorize (_as_double_1, otypes=[np.float]) return vecfunc (self)
In [49]: obj.as_double() Out[49]: fixed_pt_array([ 0., 1., 2., 3., 4.])
The values are correct, but I wanted a float array, not fixed_pt_array for output.
_______________________________________________ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion
np.array(np.ldexp(obj, -obj.frac_bits)) array([ 0., 1., 2., 3., 4.]) np.array(np.ldexp(obj, -obj.frac_bits)).dtype
I don't understand much, but if you just want to convert to a regular float array, you can just create a new array with np.array in as_double, or not? Josef dtype('float64')
type(np.array(np.ldexp(obj, -obj.frac_bits))) <type 'numpy.ndarray'>
josef.pktd@gmail.com wrote:
On Tue, Sep 29, 2009 at 10:22 AM, Neal Becker <ndbecker2@gmail.com> wrote:
This doesn't work either:
def as_double (self): import math def _as_double_1 (x): return math.ldexp (x, -self.frac_bits) vecfunc = np.vectorize (_as_double_1, otypes=[np.float]) return vecfunc (self)
In [49]: obj.as_double() Out[49]: fixed_pt_array([ 0., 1., 2., 3., 4.])
The values are correct, but I wanted a float array, not fixed_pt_array for output.
_______________________________________________ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion
I don't understand much, but if you just want to convert to a regular float array, you can just create a new array with np.array in as_double, or not?
I could force an additional conversion using np.array (xxx, dtype=float). Seems wasteful. The bigger question I have is, if I've subclassed an array, how can I get at the underlying array type? In this example, fixed_pt is really an 'int64' array. But I can't find any way to get that. Any function such as 'view' just silently does nothing. It always returns the fixed_pt_array class. Consider the fixed_pt_array method as_base(). It should return the underlying int array. How could I do this?
On Tue, Sep 29, 2009 at 10:10, Neal Becker <ndbecker2@gmail.com> wrote:
I could force an additional conversion using np.array (xxx, dtype=float). Seems wasteful.
np.asarray() will not be wasteful.
The bigger question I have is, if I've subclassed an array, how can I get at the underlying array type?
x.view(np.ndarray) The .view() method serves two purposes: to create a view onto the same memory with a new dtype but also to create a view using a different ndarray subclass. -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco
participants (3)
-
josef.pktd@gmail.com -
Neal Becker -
Robert Kern