Skip to content

Commit 0dac8b8

Browse files
committed
Fix complex dtype detection (#67) and index in equal (#66)
change _qfmt and _fxpfmt to methods
1 parent 89dc03a commit 0dac8b8

File tree

2 files changed

+84
-23
lines changed

2 files changed

+84
-23
lines changed

fxpmath/objects.py

+32-23
Original file line numberDiff line numberDiff line change
@@ -315,12 +315,14 @@ def get_dtype(self, notation=None):
315315
self._update_dtype(notation) # update dtype
316316
return self._dtype
317317

318-
_qfmt = re.compile(r'(s|u|q|uq|qu)(\d+)(\.\d+)?')
319-
_fxpfmt = re.compile(r'fxp-(s|u)(\d+)/(\d+)(-complex)?')
318+
def _qfmt(self):
319+
return re.compile(r'(s|u|q|uq|qu)(\d+)(\.\d+)?')
320+
def _fxpfmt(self):
321+
return re.compile(r'fxp-(s|u)(\d+)/(\d+)(-complex)?')
320322

321323
def _parseformatstr(self, fmt):
322324
fmt = fmt.casefold()
323-
mo = self._qfmt.match(fmt)
325+
mo = self._qfmt().match(fmt)
324326
if mo:
325327
# Q/S notation counts the sign bit as an integer bit, such that
326328
# the total number of bits is always int+frac
@@ -333,7 +335,7 @@ def _parseformatstr(self, fmt):
333335
n_word = n_frac + n_int
334336
complex_dtype = False
335337
else:
336-
mo = self._fxpfmt.match(fmt)
338+
mo = self._fxpfmt().match(fmt)
337339
if mo:
338340
signed = mo.group(1) == 's'
339341
n_word = int(mo.group(2))
@@ -570,12 +572,12 @@ def reshape(self, shape, order='C'):
570572
If an integer, then the result will be a 1-D array of that length.
571573
One shape dimension can be -1. In this case, the value is inferred from the length of the array and remaining dimensions.
572574
573-
order : {‘C’, ‘F’, ‘A’}, optional
575+
order : {'C', 'F', 'A'}, optional
574576
Read the elements of a using this index order, and place the elements into the reshaped array using this index order.
575-
‘C’ means to read / write the elements using C-like index order, with the last axis index changing fastest, back to the first axis index changing slowest.
576-
‘F’ means to read / write the elements using Fortran-like index order, with the first index changing fastest, and the last index changing slowest.
577-
Note that the ‘C’ and ‘F’ options take no account of the memory layout of the underlying array, and only refer to the order of indexing.
578-
‘A’ means to read / write the elements in Fortran-like index order if a is Fortran contiguous in memory, C-like order otherwise.
577+
'C' means to read / write the elements using C-like index order, with the last axis index changing fastest, back to the first axis index changing slowest.
578+
'F' means to read / write the elements using Fortran-like index order, with the first index changing fastest, and the last index changing slowest.
579+
Note that the 'C' and 'F' options take no account of the memory layout of the underlying array, and only refer to the order of indexing.
580+
'A' means to read / write the elements in Fortran-like index order if a is Fortran contiguous in memory, C-like order otherwise.
579581
580582
Returns
581583
---
@@ -594,12 +596,12 @@ def flatten(self, order='C'):
594596
Parameters
595597
---
596598
597-
order{‘C’, ‘F’, ‘A’, ‘K’}, optional
598-
‘C’ means to flatten in row-major (C-style) order.
599-
‘F’ means to flatten in column-major (Fortran- style) order.
600-
‘A’ means to flatten in column-major order if a is Fortran contiguous in memory, row-major order otherwise.
601-
‘K’ means to flatten a in the order the elements occur in memory.
602-
The default is ‘C’.
599+
order{'C', 'F', 'A', 'K'}, optional
600+
'C' means to flatten in row-major (C-style) order.
601+
'F' means to flatten in column-major (Fortran- style) order.
602+
'A' means to flatten in column-major order if a is Fortran contiguous in memory, row-major order otherwise.
603+
'K' means to flatten a in the order the elements occur in memory.
604+
The default is 'C'.
603605
604606
Returns
605607
---
@@ -750,7 +752,9 @@ def _update_dtype(self, notation=None):
750752
self._dtype = 'fxp-{sign}{nword}/{nfrac}{comp}'.format(sign='s' if self.signed else 'u',
751753
nword=self.n_word,
752754
nfrac=self.n_frac,
753-
comp='-complex' if (self.val.dtype == complex or self.vdtype == complex) else '')
755+
comp='-complex' if (isinstance(self.val, complex) or \
756+
self.val.dtype == complex or \
757+
self.vdtype == complex) else '')
754758
else:
755759
self._dtype = 'fxp-{sign}{nword}/{nfrac}'.format(sign='s' if self.signed else 'u',
756760
nword=self.n_word,
@@ -1014,7 +1018,7 @@ def uraw(self):
10141018
"""
10151019
return np.where(self.val < 0, (1 << self.n_word) + self.val, self.val)
10161020

1017-
def equal(self, x):
1021+
def equal(self, x, index=None):
10181022
"""
10191023
Sets the value of the Fxp using the value of other Fxp object.
10201024
If `x` is not a Fxp, this method set the value just like `set_val` method.
@@ -1025,6 +1029,9 @@ def equal(self, x):
10251029
x : Fxp object, None, int, float, complex, list of numbers, numpy array, str (bin, hex, dec)
10261030
Value(s) to be stored in fractional fixed-point (base 2) format.
10271031
1032+
index : int, optional, default=None
1033+
Index of the element to be overwritten in list or array of values by `val` input.
1034+
10281035
Returns
10291036
---
10301037
@@ -1033,10 +1040,15 @@ def equal(self, x):
10331040
"""
10341041

10351042
if isinstance(x, Fxp):
1036-
new_val_raw = x.val * 2**(self.n_frac - x.n_frac)
1037-
self.set_val(new_val_raw, raw=True)
1043+
if index is None:
1044+
raw_val = x.val[index]
1045+
else:
1046+
raw_val = x.val
1047+
1048+
new_val_raw = raw_val * 2**(self.n_frac - x.n_frac)
1049+
self.set_val(new_val_raw, raw=True, index=index)
10381050
else:
1039-
self.set_val(x)
1051+
self.set_val(x, index=index)
10401052
return self
10411053

10421054
# behaviors
@@ -1857,9 +1869,6 @@ def item(self, *args):
18571869
items = args[0]
18581870
return self.astype(item=items)
18591871

1860-
# ToDo:
1861-
# nonzero
1862-
18631872
def clip(self, a_min=None, a_max=None, **kwargs):
18641873
from .functions import clip
18651874

tests/test_issues.py

+52
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,55 @@ def test_issue_62_v0_4_7():
274274
y[0][0] = y[0][0] + 1.0
275275

276276
assert y[0][0]() == 0.0
277+
278+
def test_issue_66_v0_4_8():
279+
x = Fxp(np.array([1.25, 0.5]), dtype='S8.4')
280+
y = Fxp(np.array([2.25, 1.5]), dtype='S16.6')
281+
# x[0].equal(y[0]) # it does NOT work
282+
# x[0] = y[0] # it works
283+
x.equal(y[0], index=0) # it works
284+
285+
assert x[0]() == y[0]()
286+
287+
def test_issue_67_v0_4_8():
288+
input_size = Fxp(None, dtype='fxp-s32/23')
289+
f = [0,10+7j,20-0.65j,30]
290+
f = Fxp(f, like = input_size)
291+
292+
def FFT(f):
293+
N = len(f)
294+
if N <= 1:
295+
return f
296+
297+
# division: decompose N point FFT into N/2 point FFT
298+
even= FFT(f[0::2])
299+
odd = FFT(f[1::2])
300+
301+
# store combination of results
302+
temp = np.zeros(N, dtype=complex)
303+
# temp = Fxp(temp, dtype='fxp-s65/23')
304+
temp = Fxp(temp, dtype='fxp-s65/46')
305+
306+
for u in range(N//2):
307+
W = Fxp(np.exp(-2j*np.pi*u/N), like=input_size)
308+
temp[u] = even[u] + W* odd[u]
309+
temp[u+N//2] = even[u] - W*odd[u]
310+
311+
return temp
312+
313+
# testing the function to see if it matches the manual computation
314+
F_fft = FFT(f)
315+
316+
def test_issue_73_v0_4_8():
317+
# single unsigned value does work
318+
a = Fxp(10, False, 14, 3)
319+
b = Fxp(15, False, 14, 3)
320+
c = a - b
321+
assert c() == 0.0 # 0.0 --> correct
322+
323+
# unsigned list does not work
324+
d = Fxp([10, 21], False, 14, 3)
325+
e = Fxp([15, 15], False, 14, 3)
326+
f = d - e
327+
assert f[0]() == 0.0 # [4095.875 6.0] --> 4095.875 is the upper limit
328+
assert f[1]() == 6.0

0 commit comments

Comments
 (0)