The most efficient algorithm for calculating the total numerator of the sum of fractions

I am sure this is the right site for this question, but feel free to move it to another stackexchange site if it works better.

Suppose you have the sum of fractions a1/d1 + a2/d2 + … + an/dn . You want to calculate the total numerator and denominator, i.e. Rewrite it as p/q . We have the formula

 p = a1*d2**dn + d1*a2*d3**dn + … + d1*d2*…d(n-1)*an q = d1*d2*…*dn. 

What is the most efficient way to calculate these things, in particular p ? You can see that if you calculate it naively, that is, using the formula above, you calculate a lot of redundant things. For example, you will calculate d1*d2 n-1 times.

My first thought was to iteratively compute d1*d2 , d1*d2*d3 , ... and dn*d(n-1) , dn*d(n-1)*d(n-2) ,. .. but even this is inefficient because you end up calculating the “average” multiplications twice (for example, if n is big enough, you double calculate d3*d4 ).

I am sure that this problem can be expressed in some way, using, perhaps, some kind of graph theory or combinatorics, but I have not studied this material enough to reflect on this well.

And one note: I'm not interested in cancellation, just the most efficient way to propagate things.

UPDATE:

I should have known that people on stackoverflow assume that these are numbers, but I'm so used to my use case that I forgot to mention it.

We cannot simply "divide" an into each member. The use case here is a symbolic system. In fact, I'm trying to fix a function called .as_numer_denom() in the SymPy computer algebra system , which currently calculates this naively. See the related SymPy issue .

Separation of things has some problems that I would like to avoid. Firstly, there is no guarantee that everything will be canceled. This is due to the fact that mathematically (a*b)**n != a**n*b**n in the general case (if a and b are positive, then, for example, if a == b ==-1 and n == 1/2 , you get (a*b)**n == 1**(1/2) == 1 , but (-1)**(1/2)*(-1)**(1/2) == I*I == -1 ). Therefore, I don’t think it’s good to assume that dividing by an will cancel it in the expression (this may be practically unreasonable, I will need to check what the code does).

Secondly, I would also apply this algorithm to calculate the sum of rational functions. In this case, the members will automatically be multiplied together by one polynomial, and the "division" of each of an will include the application of the polynomial division algorithm. You can see in this case, you really want to calculate the most effective multiplication in the first place.

UPDATE 2:

I think that my concerns about the abolition of symbolic terms may be unfounded. SymPy does not override features like x**n*x**(m - n) automatically, but I think that any metrics that will be combined through multiplication will also be combined through division, so the credentials should be revoked.

There is a problem with constants that automatically distribute all additions, for example:

 In [13]: 2*(x + y)*z*(S(1)/2) Out[13]: z⋅(2⋅x + 2⋅y) ───────────── 2 

But this is the first mistake and the second can never be a problem (I think), because 1/2 will be divided into 1 and 2 according to the algorithm, which receives the numerator and denominator of each term.

However , I still want to know how to do this without “dividing” di from each term, so that I can have an efficient algorithm for summing rational functions.

+4
source share
4 answers

Instead of grouping the number n at a time, I would use pairwise addition of quotients.

  • If things are partially compensated in partial amounts, then the numbers or polynomials remain less, which speeds up the calculation.

  • You avoid the problem of computing the same product multiple times.

You can try to arrange additions in a certain way to make cancellation more likely (maybe add quotient with small denominators first?), But I don’t know if that was appropriate.

If you start from scratch, it is easier to implement, although I'm not sure if it is suitable for replacing the problematic routine in SymPy.

Edit: To make it more explicit, I suggest calculating a1/d1 + a2/d2 + … + an/dn as (…(a1/d1 + a2/d2) + … ) + an/dn .

+2
source

Compute two new arrays:

The first contains partial left multiples: l[0] = 1, l[i] = l[i-1] * d[i]

The second contains partial right multiples: r[n-1] = 1, r[i] = d[i] * r[i+1]

In both cases, 1 is the multiplicative identity of any ring in which you work.

Then each of your terms above, t[i] = l[i-1] * a[i] * r[i+1]

This suggests that multiplication is associative, but it should not be commutative.

As the first optimization, you actually do not need to create r as an array: you can make the first pass to calculate all the values ​​of l and copy the values ​​of r within a second (back) go to calculate the terms. There is no need to store r values ​​since you use them once, in order.

In your question, you say that it calculates d3*d4 twice, but it is not. It multiplies two different values ​​by d4 (one is the correct multiplication and the other is multiplication by the left), but this is not a completely repeated operation. In any case, the total number of multiplications is about 4*n , vs. 2*n multiplications and n divisions for another approach that does not work in non-commutative multiplications or non-field rings.

+3
source

If you want to calculate p in the above expression, one way to do this would be to multiply all the denominators (in O (n), where n is the number of fractions), allowing this value to be D Then, iterate over all fractions and for each fraction with the numerator a i and the denominator d i , calculate a i * D / d <sub> javspom>. This last term is equal to the product of the numerator of the fraction and all denominators other than its own. Each of these terms can be calculated O (1) times (if you use hardware multiplication, otherwise it may take longer), and you can sum them all in O (n) time.

This gives the O (n) -time algorithm for calculating the numerator and denominator of the new fraction.

+2
source

I was also told that you can manually supplant common denominators and combine these trivially without multiplication.

0
source

All Articles