Multiply a Numpy array by a scalar to make every element an integer
Asked Answered
A

2

2

I have the following Numpy array.

a = np.array([0.1, 0.9, 0.17, 0.47, 0.5])

How can I find a number such that, when multiplied by the array, turns every element into an integer?

For example, in this case, that number should be 100 because a times 100 would make every element an integer.

>>> a * 100
array([10., 90., 17., 47., 50.])

I have tried taking 10 to the power of the longest decimal length. However, I need to find the smallest possible number (and it has to be greater than 0).

b = np.array([1.0, 0.5, 0.25, 0.75, 0.5])

As a result, that number should be 4 instead of 100 in this case.

>>> b * 4
array([4., 2., 1., 3., 2.])
Arthur answered 31/10, 2021 at 8:34 Comment(2)
If you want the smallest possible number, then for the first array, the number shouldn't be 100. It should be 20. np.array([0.1, 0.9, 0.25, 0.75, 0.5]) * 20 == array([2.0, 18.0, 5.0, 15.0, 10.0])Multifoliate
@Multifoliate Sorry, I was just bad at giving examples. I have fixed it.Arthur
T
3

Start with your strategy. Get the minimal power of 10 that makes your array integer. Then convert it to an integer and get the common divisor. The number you want is the power of 10 divided by the common divisor:

b = np.array([1.0, 0.5, 0.25, 0.75, 0.5])
d = np.gcd.reduce((b * 100).astype(int))

d is 25 here, and the number you want is 100/254.

Tamikotamil answered 31/10, 2021 at 9:18 Comment(1)
It does work… 0.001 would be multiplied by 1000 leaving you with 1. if you then did 1000/1 it would equal 1000. Can you describe how it didn’t work?Commend
J
0

The accepted answer can be extended by using import fractions so that it includes finding the "tolerance", i.e., the "minimal power of 10 that makes the array integers". This makes the solution much easier for arbitrary real-valued floats.

Here is the original example with the current accepted answer:

b = np.array([1.0, 0.5, 0.25, 0.75, 0.5])
d = np.gcd.reduce((b * 100).astype(int))
print(100/d, 100/d*b)

Output: 4.0 [4. 2. 1. 3. 2.]

If the minimal power of 10 is not adjusted, then the following example does not work with the current accepted answer:

b = np.array([1./5, 2./11, 3./15, 4./9, 5./21])
d = np.gcd.reduce((b * 100).astype(int))
print(100/d, 100/d*b)

Output: 100.0 [20. 18.18181818 20. 44.44444444 23.80952381]

But with this solution, you do not need to find the minimal power of 10 first:

b = np.array([1.0, 0.5, 0.25, 0.75, 0.5])
d = np.lcm.reduce([fractions.Fraction(x).limit_denominator().denominator for x in b])
print(d, d*b)

b = np.array([1./5, 2./11, 3./15, 4./9, 5./21])
d = np.lcm.reduce([fractions.Fraction(x).limit_denominator().denominator for x in b])
print(d, d*b)

It still works with the original example, output: 4 [4. 2. 1. 3. 2.]

But it also works with the new example, output: 3465 [ 693. 630. 693. 1540. 825.]

As pointed out in a comment (from Mark Dickinson) to the accepted answer here, it may not work for fractions with denominators exceeding 1 million.

Joiner answered 3/1 at 9:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.