Moderators: phlip, Moderators General, Prelates
def pascal():
r = 0
l = [1]
yield l
while True:
l = [1] + [ l[i] + l[i+1] for i in range(r) ] + [1]
r += 1
yield l
def triangular(n):
if n == 0:
while True:
yield 1
else:
g = triangular(n-1)
a = 0
while True:
a += g.next()
yield a
# math.factorial() requires v2.6 or later
from math import log, factorial
from itertools import izip
import sys
# binomial coefficient
# also the nth row, kth column of pascal's triangle
# or n choose k
def bc(n,k):
return factorial(n)/(factorial(n-k)*factorial(k))
def pascal():
r = 0
l = [1]
yield l
while True:
l = [1] + [ l[i] + l[i+1] for i in range(r) ] + [1]
r += 1
yield l
def digits(n):
return int(log(n)/log(10))+1
rows = int(sys.argv[1])
widths = [digits(bc(rows-1, i)) for i in range(rows)]
for i,row in izip(range(rows), pascal()):
print ' '.join(['%%%dd'%(w,) for w in widths[:i+1]]) % tuple(row)
0 % python pascal.py 10
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
def performLazyMap(f, xs):
return map(lambda x: lambda: f(x), xs)
list = [0, 1, 2, 3, 4, 5]
lazyList = performLazyMap(lambda x: x*3, list)
print lazyList[3]() # outputs 3*3 = 9# We need lazy lists, so we need to teach Python how to make those
# an empty list; also, list terminator
def null(b):
return True if b==0 else null
# list creator
# cdr should always be wrapped in a lambda expression
def cons(car, cdr):
forced = False
def f(b):
nonlocal forced
nonlocal cdr
if b < 0:
return car
elif b == 0:
return False
elif not forced:
forced = True
cdr = cdr()
return cdr
return f
def head(f):
return f(-1)
def tail(f):
return f(1)
def isNull(f):
return f(0)
# We also need a convenient way to access members of a lazy list
def get(list, pos):
while pos > 0:
list = tail(list)
pos = pos-1
return head(list)
# And a few ways to work with a list would be nice
def lazyMap(f, xs):
return cons(f(head(xs)), lambda: null if isNull(xs) else lazyMap(f, tail(xs)))
def zipWith(f, xs, ys):
return cons(f(head(xs), head(ys)), lambda: null if isNull(xs) or isNull(ys) else zipWith(f, tail(xs), tail(ys)))
def iterate(f, x):
return cons(x, lambda: iterate(f, f(x)))
naturals = iterate(lambda x: x+1, 0)
print(get(naturals, 1000))
fibs = null
fibs = cons(1, lambda: cons(1, lambda: (zipWith(lambda x, y: x+y, fibs, tail(fibs)))))
print(get(fibs, 1000))
def nextRow(row):
def modZipWith(f, xs, ys, d):
"""The same as zipWith, except that we append a default value if any are missing"""
x = d if isNull(xs) else head(xs)
y = d if isNull(ys) else head(ys)
return cons(f(x, y), lambda: null if isNull(xs) and isNull(ys) else (modZipWith(f, tail(xs), tail(ys), d)))
return modZipWith(lambda x, y: x+y, cons(0, lambda: row), row, 0)
pascals = iterate(nextRow, cons(1, lambda: null))
def choose(n, m):
return get(get(pascals, n), m)
print ("100 choose 50 =", choose(100, 50))
def memoize(f):
mem = {}
def ret(x):
nonlocal mem
if not x in mem:
mem[x] = f(x)
return mem[x]
return ret
# Let f be some big hairy function
memoizedF = memoize(f)
def fib(n, mem = {0:0, 1:1}):
if n in mem:
return mem[n]
mem[n] = fib(n - 1) + fib(n - 2)
return mem[n]Lothar wrote:Indeed, memoization seems to be what you want to do. Another way is for example:
- Code: Select all
def fib(n, mem = {0:0, 1:1}):
if n in mem:
return mem[n]
mem[n] = fib(n - 1) + fib(n - 2)
return mem[n]
Ben-oni wrote:*shudder* Don't do that. It's not tail-recursive, and you will exceed your stack space.
def gcd(n,m):
if m*n==0: return m+n
if m>n:
k=m
m=n
n=k
return gcd(m,n-m)
print gcd(1000,1)
skeptical scientist wrote:I didn't think Python optimized tail-recursions to not overflow the stack.
b.i.o wrote:skeptical scientist wrote:I didn't think Python optimized tail-recursions to not overflow the stack.
It doesn't.
skeptical scientist wrote:Ben-oni wrote:*shudder* Don't do that. It's not tail-recursive, and you will exceed your stack space.
If it were tail-recursive, would that help? I didn't think Python optimized tail-recursions to not overflow the stack.
Here's a tail-recursive implementation of a gimped* Euclidean algorithm that overflows the stack (for me, running python 2.6.1 with mac defaults):
- Code: Select all
def gcd(n,m):
if m*n==0: return m+n
if m>n:
k=m
m=n
n=k
return gcd(m,n-m)
print gcd(1000,1)
def t_gcd(n, m):
if m*n==0: return lambda: m+n
if m>n: return lambda: t_gcd(n, m-n)
return lambda: t_gcd(m, n-m)
def trampoline(f):
def g(*args):
k = f(*args)
while callable(k):
k = k()
return k
return g
gcd = trampoline(t_gcd)def makeTailRecursive(funName):
f = globals()[funName]
def tF(*args): return lambda: f(*args)
def g(*args):
globals()[funName] = tF
k = f(*args)
while callable(k):
k = k()
globals()[funName] = g
return k
globals()[funName] = g
makeTailRecursive("gcd")
print(gcd(1000, 1))
OmenPigeon wrote:That's basically it, except as far as I can tell it isn't guaranteed by the language, it's guaranteed by Guido.
EvanED wrote:Guido controls CPython, not PyPy etc.
OmenPigeon wrote:EvanED wrote:Guido controls CPython, not PyPy etc.
Sure, but it's not entirely that simple. As he mentioned in that blog post, tail calls are a feature, not an optimization.
Adding them to a python implementation means that you can now write programs in one implementation of Python that won't execute correctly in others[1]. I'm not in the position of developing any Python fork, but if I were, I'd be really, really careful about letting my users write code that couldn't be used in CPython.
for key in (key for key in mydict.keys()):
# do stufffor key in mydict.keys():
# do stuff(Python's reduce is actually a fold in disguise, I think, although I don't recall ever having used it. I separate the two because I think there's a clear distinction between the two and I think they're both useful functions in their own right, and it's much easier to be clear this way.)
int main() {
int input=0;
while(input<1 || input>10) {
printf("Please enter a number between 1 and 10: ");
scanf("%d", &input);
}
printf("Your input was %d\n",input);
}rand()%Nrand()/(1+RAND_MAX/N)srand(time(NULL));skeptical scientist wrote:For example, what's a good way to generate a random number in a specified range? Some suggestions use expressions like
- Code: Select all
rand()%N
to get a number in the range [0,N-1], but this clearly won't be uniform. (For example, if rand() returned numbers in the range [0,65535], and you used this method to get a random number in the range [0,40000], the numbers in 0-25534 would be each be twice as likely as numbers in 25535-40000.)
rand() / (double) RAND_MAX * (high-low) + lowAlso, how can I see my random number generator? The only suggestion I found online that works for my architecture was
- Code: Select all
srand(time(NULL));
However, the results for this are laughably bad, since the first random number, at least, appears completely predictable.
#include <stdlib.h>
#include <stdio.h>
int main() {
srand(time(NULL));
printf("%d\n", rand());
return 0;
}#include <stdlib.h>
#include <stdio.h>
int main() {
srand(time(NULL));
printf("%d\n", rand());
srand(time(NULL));
printf("%d\n", rand());
return 0;
}skeptical scientist wrote:However, the results for this are laughably bad, since the first random number, at least, appears completely predictable.
EvanED wrote:There's still a fundamental problem where it's mapping RAND_MAX integers onto a smaller range, so there will be numbers that are more probable than others, but they're not concentrated in one part of the range. If the (high-low) bit is small relative to RAND_MAX, the probability difference will be low as well.
Also, how can I see my random number generator? The only suggestion I found online that works for my architecture was
- Code: Select all
srand(time(NULL));
However, the results for this are laughably bad, since the first random number, at least, appears completely predictable.
In what sense? It shouldn't be. If you run this a few times (at least a second apart), do you get different results?
skeptical scientist wrote:Generators seem great when you want to iterate over a list, and generate it as you go. But what if you want to use the list in more complicated ways? If you keep using the bit you've already generated, but occasionally you need to generate some new bit? What if instead of a list you want a mapping type, like a dictionary? What I have in mind is something like the following:
I have a function, f, which I need to compute for some large number of inputs, in such a way that I'm probably going to need to compute f on the same input some large number of times. Moreover, computing f is expensive. So to save time (at the expense of memory), I will use a dictionary to store computed pairs {n : f(n)}. Now, every time I want to compute f(n), I check whether n is a key in the dictionary. If it is, I return the corresponding value. Otherwise, I compute f, return f(n), and store the pair {n : f(n)} in my dictionary.
In certain applications, this could be much faster than precomputing the entire dictionary, and also much faster than computing f(n) every time you need it. I can do it with global variables, and I guess it's not too ugly that way, but I feel like there should be a nice local way of doing this.
>>> def a():
... s = range(5)
... def b():
... s.append('z')
... print s;b();print s
...
>>> a()
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 'z']
PM 2Ring wrote:Python stuff.
On the issue of local variables, remember that you can define functions inside functions in Python, and such functions have read access to the variables of the containing function.
C stuff.
scanf() is evil. It's probably turned off more C newbies than any other feature of C. There are rarely any good reasons to use it.
The algorithm used by rand() isn't specified by the standard, and some old versions of rand() were pretty crummy. If you'd like to allow the user to specify random number seeds and you want to make your program portable, don't use the standard library's rand(), provide your own PRNG, preferably something modern like Mersenne Twister.
#include <iostream>
int main() {
using namespace std;
int input=0;
while(input<1 || input>10) {
cout << "Please enter a number between 1 and 10: ";
cin >> input;
}
cout << "Your input was " << input << endl;
return 0; // (added for correctness)
}Jplus wrote:FYI: when you do need a better PRNG, it will be most convenient for you to look for a library. For example Boost.Random. It's C++, not C, but personally I think C++ would fit your needs better anyway. Otherwise, a PRNG library in pure C probably also exists.
Now that I mention it anyway, here's how your input/output problem would be solved in C++:
- Code: Select all
#include <iostream>
int main() {
using namespace std;
int input=0;
while(input<1 || input>10) {
cout << "Please enter a number between 1 and 10: ";
cin >> input;
}
cout << "Your input was " << input << endl;
return 0; // (added for correctness)
}
EvanED wrote:Jplus wrote:Stuff[/code]
FWIW, no it's not; that has the same problem as his original question. (Try entering something that isn't a number.)
#include <iostream>
int main() {
using namespace std;
int input=0;
while(input<1 || input>10) {
cout << "Please enter a number between 1 and 10: ";
cin >> input;
if (cin.fail()) {
cin.clear();
cin.ignore(100, '\n');
input = 0;
}
}
cout << "Your input was " << input << endl;
}EvanED wrote:Also, fun fact: in C++ you don't technically need the 'return 0;' at the end of 'main'; if execution falls off the end of main, it acts as it was there. ('main' is special that way; this doesn't apply to other functions, and doesn't apply to plain C.)
skeptical scientist wrote:PM 2Ring wrote:Python stuff.
On the issue of local variables, remember that you can define functions inside functions in Python, and such functions have read access to the variables of the containing function.
I didn't know that, actually. That's interesting.
def int_sqrt(x): #returns the integer part of the square root of x, using a stupid algorithm. Only suitable near the limit of floating point accuracy.
y=int(x**0.5)
while y**2<x:
y+=1
while y**2>x:
y-=1
return y
for i in range(10000000):
error=int(i**0.5)-int_sqrt(i)
if error: print i,errorfor i in range(10000000):for i in xrange(10000000):letterX wrote:For 3, have you tried changing
- Code: Select all
for i in range(10000000):
to
- Code: Select all
for i in xrange(10000000):
The thing about "range" is that it actually generates a list containing all numbers from 1 to n. As opposed to xrange, which just returns a generator which iterates through all numbers from 1 to n, without actually building the entire list.
skeptical scientist wrote:1. Is there any difference between x**0.5 and math.sqrt(x), and, if so, what is the difference?
skeptical scientist wrote:1. Is there any difference between x**0.5 and math.sqrt(x), and, if so, what is the difference?
skeptical scientist wrote:2a. Can I can assume int(x**0.5) is the integer part of the square root of x so long as x < (sys.float_info.radixsys.float_info.mant_dig)2? If you check just the powers of 10, int(x**0.5) first fails to give the integer part of the square root of x for x=1033, which is about what you would expect if this were true.
skeptical scientist wrote:2b. If not, for what values of x can I safely assume that int(x**0.5) is the integer part of the square root of x? (Basically, if I care about precise integer arithmetic on long integers, when do I need to worry about writing my own integer square root function?)
jareds wrote:These aren't really noob questions.
from math import sqrt
i=0
while 1:
i+=1
if int(sqrt(i**2-1))!=i-1: break
for j in xrange((i-1)**2,i**2):
if int(sqrt(j))!=i-1: break
print "the least j for which int(sqrt(j)) is not the integer part of the square root of j is",jcjmcjmcjmcjm wrote:If it can't be done in an 80x24 terminal, it's not worth doing
skeptical scientist wrote:The main reason I'm asking this is I'm writing a lot of programs that need to find exact answers to mathematical questions (e.g. project Euler problems), I'm using int(sqrt(x)) a lot, sometimes on very large numbers, and I'm always a bit worried that I'm going to get the wrong answer because of inaccurate floating point arithmetic. I suspect I will end up needing to write my own exact int_sqrt() function at some point, I just want to know at what point I should bother.
Users browsing this forum: Bakstoola, GuetraGma and 13 guests