1

I'm asked to make a program that calculates the addition of two polynomials of n and m degrees. I made two dictionaries (one for the first polynomial and the other is for the other polynomial) since each one has the coefficients as values and degrees as keys so that I can check whether the keys from both dictionaries are identical, then I can sum their values. But I don't know why I always get an error. My code so far is:

class poly:
    def __init__(self, L=[], D=[]):
       self.coef=L
       self.deg=D

    def __add__(self,L2):
       if len(self.coef)>len(self.deg):
          dec=dict(zip(self.deg,self.coef))
          dec[0]=self.coef[-1]

       else:
          dec=dict(zip(self.deg,self.coef))

       Dec1=dec

       if len(L2.coef)>len(L2.deg):
          dec=dict(zip(L2.deg,L2.coef))
          dec[0]=L2.coef[-1]
       else:
          dec=dict(zip(L2.deg,L2.coef))

       Dec2=dec
       p=[]

       if len(Dec2)>len(Dec1):
          for i in Dec2:
            if i in Dec1:
                s=Dec1[i]+Dec2[i]
                p=p+[s]
            else:
                p=p+p[Dec2[i]]

          for x in Dec1:
            if x in Dec2:
                p=p
            else:
                p=p+[dec1[x]]
       return(poly(p))

       if len(Dec2)<len(Dec1):
         for x in Dec1:
             if x in Dec2:
                g=Dec1[x]
                p=p+[g]
             else:
                p=p+[Dec1[x]]

         for m in Dec2:
            if m in Dec1:
                p=p
            else:
                p=p+[Dec2[m]]
       return (poly(p))

This code doesn't work for all my examples such as

>>> p=poly([2,4,7,34],[6,4,2])
>>> p1=poly([6,3,7,2,8],[8,4,2,1])
>>> p2=p+p1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    p2=p+p1
  File "poly.py", line 31, in __add__
    p=p+p[Dec2[i]]
IndexError: list index out of range
>>> #The numbers in the first list is the coefficients and the second list is for degrees

This doesn't work! But it worked when I've done the addition without using class method. I'm a beginner and I did my best to fix the problem.

Another question is how to write the def str for my code? I really don't have any idea what I should write in the beginning. I'm sorry guys but I'm new in programming and I need an easy code such as mine.

Ren
  • 1,111
  • 5
  • 15
  • 24
  • Not that its causing your particular problem, but be careful using `[]` as a default value in `__init__` (or anywhere else, for that matter): http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument – lvc Apr 28 '12 at 23:04
  • 2
    Also, it might make more sense to store your polynomial as a single list of coefficients, so that `x^3 + 2` has coefficients `[1, 0, 2]`. – lvc Apr 28 '12 at 23:18
  • I did both! first my init was without [] but it didn't work. So i will get ride of it. Sorry for not having mentioned that i'm expecting that the user enters a string!! – user1354396 Apr 28 '12 at 23:45
  • @user1354396: Have you printed out the values you are indexing `Dec2` with in the line that throws that error? I bet you'll find they're not the ones you're expecting ;) – Joel Cornett Apr 29 '12 at 00:08

1 Answers1

3
  1. By common convention, class names should be capitalized (ie Poly)
  2. You have __add__ doing a lot of stuff that has nothing to do with adding. This should be a warning sign.
  3. A lot of __add__'s work is mucking about with the data storage format. Maybe you should use a better storage format, one which won't need so much reshuffling?
  4. You have a lot of repetitive chunks of code in __add__; this is usually an indicator that the code should be factored into a subroutine.
  5. You have this object (self) making changes to the internal details of another object (L2) - another bad smell.

If you move the normalization code for self (if len(self.coef) > len(self.deg) ...) from __add__ into __init__, this will solve #2, #3, half of #4, and #5 all in one go (you no longer have to "do to" L2, it will "do to" itself).

If you realize that it's pretty much irrelevant whether len(Dec1) > len(Dec2) or not, you can get rid of another block of redundant code. This fixes the other half of #4. Suddenly __add__ shrinks from 48 lines of code to about 12, and becomes much easier to understand and debug.

For sake of comparison:

from itertools import izip_longest, chain, product
from collections import defaultdict

class Poly(object):
    def __init__(self, coeff=None, power=None):
        if coeff is None: coeff = []
        if power is None: power = []
        self.d = defaultdict(int)
        for c,p in izip_longest(coeff, power, fillvalue=0):
            if c != 0:
                self.d[p] += c

    @classmethod
    def fromDict(cls, d):
        return cls(d.itervalues(), d.iterkeys())

    @property
    def degree(self):
        return max(p for p,c in self.d.iteritems() if c != 0)

    def __add__(self, poly):
        return Poly(
            chain(self.d.itervalues(), poly.d.itervalues()),
            chain(self.d.iterkeys(),   poly.d.iterkeys())
        )

    def __mul__(self, poly):
        return Poly(
            (cs*cp for cs,cp in product(self.d.itervalues(), poly.d.itervalues())),
            (ps+pp for ps,pp in product(self.d.iterkeys(),   poly.d.iterkeys()))
        )

    def __call__(self, x):
        return sum(c*x**p for p,c in self.d.iteritems())

    def __str__(self):
        clauses = sorted(((p,c) for p,c in self.d.iteritems() if c != 0), reverse=True)
        return " + ".join("{}x^{}".format(c,p) for p,c in clauses) or "0"

Note that:

  1. Each method is short and does only things relevant to what it is supposed to accomplish.
  2. I purposefully wrote __init__ to be very fault-tolerant; it will cheerfully accept multiple coefficients of a given power and sum them. This allowed me to greatly simplify __add__ and __mul__, basically just throwing all the resulting clauses at a new Poly and letting it clean them up again.
  3. I have included a minimal implementation of __str__, which will result in moderately ugly output like 5x^2 + -2x^1 + -5x^0. You may wish to add special handling for negative coefficients and powers of 1 or 0, to make it produce 5x^2 - 2x - 5 instead.
  4. This is for the purpose of understanding, not plagiarism; do not submit it to your teacher as is, he will never in a million years believe you actually wrote it ;-)
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99