Factorial


#1

So I’ve been banging my head against this for days.
The first part ending with print fact generate the correct list
But the second part turns out like scrambled eggs.
Help!!!

def factorial(x):  
  y= 0
  fact =[]
  while x-y <= x and x-y >= 1:
    fact.append(x-y)
    y+=1
  print fact   
  for i in range(len(fact)):
    while len(fact) <=x and len(fact)>0:
      factorl = 0
      factorl +=fact[i]
      len(fact)-1
  return factorl	

print factorial(3)

#2

What’s the reasoning for having a loop inside another loop for computing factorial? (Doesn’t seem to match what factorial is)

And then this

len(fact)-1

That’s a no-op, has no effect.

Also, what is the reason for using a list? (Could the numbers be consumed immediately and then discarded instead?)


#3

My thought process was not to try to parallel process it but split the problem in two.
I’m seen other solutions but they were much more elegant and therefore unintuitive to a newbie
Part 1, generate the list and Part 2 sum them.
My Part 2 starts with the for statement. First I tried to iterate through the list
checking to make sure I hadn’t run out of numbers (what happens if I omit this? Not sure)
That’s what the while statement is for. Then the rest attempts to add each item held to a running total

That line len(fact) - 1 was intended to reduce the scope by 1 making sure it didn’t always start with the maximum number of list entries?

Makes sense?


#4

Whoops, got distracted by something else for a good 15 minutes there.

I agree, ignore other people’s solutions. Better to figure out a solution from where you’re currently at.
And doing one thing at a time is also an excellent method… Which you should always be applying.

I still don’t agree with storing them in a list, rather using them as soon as they’re generated, but right now that’s not very important (we have other things to fix first)

Going through those numbers that you generated, from the start to the end, that’ll be one loop. Having two loops, especially one inside another, doesn’t match this task at all!
Nesting loops like that is something you would do if you had a 2D data structure (rows and columns)

And the len-1 part, it certainly won’t resize the list, but it also won’t get stored anywhere, you’d need a variable for that

And yes. You’re making plenty of sense. Your code not so much yet, but you/we will sort that out


#5

Checking whether your numbers are right sounds like something you ought to be doing when creating them in the first place. Or rather, they should be created correctly so that there’s no checking to be done (computers can make mistakes but it takes some serious disturbance or faulty hardware for that to happen, it’s very rare, we can ignore this chance for nearly all applications)

Oh and factorial is 1…n multiplied to each other, not added


#6

So I went back to the drawing board so-to-speak after carefully reading you comment :stuck_out_tongue_winking_eye: (you must be a really awesome teacher, I totally missed the earlier hidden suggestion in your first response) tried re-conceiving the entire thing
Came up with this

def factorial(x):
  while (x-1) <= x and (x-1)>=1:
    fctrl = 0
    fctrl+=x * (x-1)
    x-=1
  return fctrl
  
print factorial(4)

But the console is choking on this also. I'll get past this sometime in this lifetime, lol.
PS I appreciate your not saying 'here's the code that works'. It's in IMHO a terrible attitude in any instruction to grow exasperated with the pupil and just throw the answer at them.

#7

How often do you set fctrl to 0?

You’re both adding and multiplying. Might need to re-read what factorial is (the first paragraph of wikipedia ought to do it), or perhaps not, but this isn’t something one would do while computing factorial

One loop. Yes. If you compute factorial manually in your head or on paper then you’ll be doing one pass - one loop.

Your condition in the loop tests two things. Without… even reading it (call me lazy) I suspect only one of them will ever get hit. Actually scratch that, I read the first one and it has x on both sides in a way that cancels out the x so it’ll always have the same result
edit: and the second one has a 1 on both sides, surely one of them could be moved to the other side so that you’ve got x by itself


#8

You get some number x, right.

We assume it’s a number. It’s an integer even. If it’s not, then it’s the caller’s fault, we don’t care.

Factorial is also only defined for non-negative numbers. So we might or might not check whether that’s the case. Or not care again, we can consider it the caller’s fault if it’s not, that’s fine.

The remaining calculation will always be done the same way, it’ll loop from 1 to x, or from x to 1 perhaps, and the end condition is always going to be the same, either that it reached 1, or it reached x (gotta make sure it doesn’t do one too many or one too few though) <- that’s why I say that there’ll probably only be one condition that needs to be met for the loop. There’s only one thing we’re waiting for

Another note… Your program will in most cases do the same thing that you’d do manually. So when you write code you’re describing those same steps. Observing how you do a task manually will tell you a lot about what your code should look like (for example, having one loop, not 3)


#9

I haven’t given up. I appreciate your guidance.
My current solution looks like this but Python does not like my conditional statement testing equivalence between my step (y) and the input x

def factorial(x):
  y=1
  
  for y <= x:
    multiplier = x-y
    x*= multiplier
    y+=1
        
  return x
  
print factorial(4)

#10

Read 4.1, 4.2, 4.3 - and/or the while statement, which I think is what you were trying to use

https://docs.python.org/tutorial/controlflow.html#if-statements

hi o/


#11

The link really only shows how for-statements are used - which explains why your code doesn’t work.
And they can be combined with the range function to produce numbers
The while statement is closer to what you’ve currently got, so feel free to stick with that

Also, you may find it easier to not change x’s value, and instead generate all the numbers you need, and multiply to a separate variable where you keep the result

Anyway. I’m going out for groceries. Pile up questions.


#12

If you have a look at the numbers used while computing factorial, it’s just counting up from 1 to x. There’s no subtraction, just adding 1. (Or subtracting 1, if you start from x and go down to 1)

A while-statement can be used to manually increase the number, or a for-loop using the range function can be used.

If you start by writing a program that counts from 1 to x, then you’re nearly done - just the multiplying into the result remains.

After that you might go back to what you had at the start of this thread, compare intentions, maybe fix it.
The point is really that you should decide what should happen, and then write code which does exactly that.
And until you’ve convinced yourself of that a series of steps will produce the correct result, you probably shouldn’t write a single line.


#13

Its not the logic that stumps me, it’s ‘conveying the contents of my heart’ lol
I know that I love the girl, I just don’t know how to get the feeling in my head into human (python) words.
I understand for instance 3! to mean 3 x 2 x 1
In Python this translates for me as "for y in range(1,(x+1)) which in the case of 3 as input should yield 1, 2, 3
The next challenge for me is multiplying the numbers, so far I can only think of
x*= y by which I intend take 3 and multiply it by 1 and 2 and so forth until x = y
I know the last line to be incorrect but my mind has never been bent in this direction before.


#14

That sounds correct to me, so long as you don’t mean that you should start with 3 and end with 3 cause then you’d have 1 * 2 * 3 * 3

Looking at that, 1 * 2 * 3 * 3, it’s easy to tell that you either should start with some other number than 3, or if you do start with 3, don’t include it again… Or even divide afterwards. But why do something extra and then undo it later, just complicated. Better to get it right from the start.

Remember my suggestion on leaving x unmodified and having a separate results variable?
I would only modify x if I was decreasing it towards 1 instead of counting upwards

You can also add prints which say each action that’s happening, for example each generated number and the value of the result after each multiplication - that’ll tell you everything going on and it’ll be easy to tell if and where something isn’t being done right and adjust as needed

before=3, n=1, after=3   <-- clearly wrong initial value
before=3, n=2, after=6
before=6, n=3, after=18
      ^    ^        ^
      |    |        the multiplication is being done correctly
      |    the counting is right, so no need to change that
      the value from last iteration is carrying over correctly
      except for that the initial value isn't right

#15

I’m not sure what your example is demonstrating - and I’ve re-read it Lord-knows how many times. I did adopt the adding print suggestion which was revelatory. After reviewing the functions section I came up with

def factorial(x):
    
  y=1
  fctr = []
  #if y<=x:
  for e in range(1,x+1):
    fctr.append(e)
  print fctr
  y*=fctr[e]

  return y
  
print factorial(3)

I think y*=fctr[e] conveys the missing piece in my head but Python swears somehow I’m committing an index violation, specifically IndexError: list index out of range


#16

By my example I meant that you’d write out everything in some readable fashion, and compare it to what you had already decided should be happening, then make conclusions about which parts of the code was doing what they ought to be doing

…When debugging something bigger you’d start printing somewhere in the middle of the process and try to determine if the problem is earlier or later and then add prints somewhere in the middle of that - quickly narrowing down where the problem is

And yeah, consider the last value of e in the loop, and the size of the list and whether e is a valid index

And you really ought to be multiplying once for each number, so that would be inside a loop. And again, a list isn’t really needed cause the numbers can be used immediately (storing in a list isn’t any easier than using it immediately, hence why I don’t agree with using a list, doesn’t make anything simpler)

Yes. Printing is useful. Don’t ever guess, find out, look. Print does that.


#17

Got it!!!

def factorial(x):
    
  y=1
  fctr = []
  
  for e in range(1,(x+1)):
    y*=e

  return y
  
print factorial(0)

Thanks for staying with me - I think part of my problem is I often hit a tough case and then avoid practice which leads to necessity of revising nearly the entire course to come up to speed - much like learning a language you don’t use regularly. I truly appreciate your sticking this out. I’m definitely committed to seeing this through, been stuck at 66% for months. Whew! On to the next one!


#18

Another way of implementing factorial is by using the fact that factorial(x) is equal to x * factorial(x-1).
So you would literally write that in the code, and you can easily tell that it’ll keep calling itself with one less each time. All that remains is to hard-code factorial for the lowest defined input (x=0) as a special case which will break the loop and then all those function calls that are waiting can start returning back to their callers


#19

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.