I am converting a matlab code to Python. In matlab there is a line which converting the complex number to the int16:
real = int16(real(-3.406578165491512e 04 9.054663292273188e 03i));
imag= int16(imag(-3.406578165491512e 04 9.054663292273188e 03i));
real= -32768
imag=9055
In python I have tried this:
real = np.int16(round(np.real(-3.406578165491512e 04 9.054663292273188e 03j)))
imag = np.int16(round(np.imag(-3.406578165491512e 04 9.054663292273188e 03j)))
real= 31470
imag=9055
The results are different (I have had many other values such as (1.815808483565253e 04 3.533772674703890e 04j) with different answer!) would you please help me to get the same answer?
CodePudding user response:
The MATLAB output has saturated at intmin('int16') = -32768
(docs), i.e. the most negative value it can represent as an int16
variable.
Python has the same range for int16
(docs), but instead of saturating at the most negative value it has experienced underflow, wrapping around to the top of the range
k = round(-3.406578165491512e 04) = -34066
k = k (32768*2) = 31470
You could get around this by enforcing whichever of these is your preferred behaviour when the inputs are still floating point values, and then when the input is within the range -32768 to 32767
you can cast it to int16
.
CodePudding user response:
Wolfie gets at the difference, this is about how to solve it. If you're OK with clipping, then you can use iinfo to get the min and max values of an integer type (or hard-code it, if you know you won't be changing it from int16 ever) and then use clip to constrain the float to be within those bounds before casting it.
n = -3.406578165491512e 04
ii = np.iinfo(np.int16)
print(f"min = {ii.min}") # min = -32768
print(f"max = {ii.max}") # max = 32767
np.int16(np.clip(n, ii.min, ii.max))
# -32768
IMPORTANT NOTE: This is only reliable if the size if your float is larger than the size of the int, because it relies upon being able to represent ii.max
exactly as a float. See here for a discussion of when this is not true.
Here's an example of that failing
n = np.float64(1e100)
ii = np.iinfo(np.int64)
print(f"max: {ii.max}") # max = 9223372036854775807
clipped = np.clip(n, ii.min, ii.max)
print(f"clipped to: {int(clipped)}") # clipped to: 9223372036854775808
print(f"as int: {np.int64(clipped)}") # as int: -9223372036854775808
(This happens because ii.max cannot be represented as a float. Past 9007199254740992, we lose the 1's place of precision and can only specify even integers, so the bounds of the clipping become incorrect.)