Generator/Exponential: Difference between revisions

(→‎{{header|Ruby}}: Also show the correction solution with all three generators.)
(→‎{{header|E}}: Add C using libco.)
Line 13:
'''See also'''
* [[wp:Generator (computer_science)|Generator]]
 
=={{header|C}}==
==={{libheader|libco}}===
 
libco is a tiny library that adds ''cooperative multithreading'', also known as ''coroutines'', to the C language. Its <tt>co_switch(x)</tt> function pauses the current thread and resumes the other thread <tt>x</tt>.
 
This example adds <tt>next64()</tt> and <tt>yield64()</tt>, to generate 64-bit integers. <tt>next64()</tt> switches to a generator. Then the generator passes some 64-bit integer to <tt>yield64()</tt>, which switches to the first thread, where <tt>next64()</tt> returns this 64-bit integer.
 
<lang c>#include <inttypes.h> /* int64_t, PRId64 */
#include <stdio.h> /* printf() */
 
#include <libco.h> /* co_active(), co_create(), co_switch() */
 
 
 
/* A generator that yields values of type int64_t. */
struct gen64 {
cothread_t giver; /* this coroutine calls yield64() */
cothread_t taker; /* this coroutine calls next64() */
int64_t given;
};
 
/* Yields a value. */
inline void
yield64(struct gen64 *gen, int64_t value)
{
gen->given = value;
co_switch(gen->taker);
}
 
/* Returns the next value that the generator yields. */
inline int64_t
next64(struct gen64 *gen)
{
gen->taker = co_active();
co_switch(gen->giver);
return gen->given;
}
 
struct gen64 *entry64;
 
/*
* Creates a coroutine for the generator. The first call to next64(gen)
* will enter the coroutine; the entry function must copy the pointer
* from the global variable struct gen64 *entry64.
*/
inline void
gen64_init(struct gen64 *gen, void (*entry)(void))
{
gen->giver = co_create(4096, entry);
entry64 = gen;
}
 
 
 
/* Defines a static entry function for a coroutine. */
#define ENTRY(name, code) static void name(void) { code; }
 
/*
* Generates the powers 0**m, 1**m, 2**m, ....
*/
void
powers(struct gen64 *gen, int64_t m)
{
int64_t base, exponent, n, result;
 
for (n = 0;; n++) {
/*
* This computes result = base**exponent, where
* exponent is a nonnegative integer. The result
* is the product of repeated squares of base.
*/
base = n;
exponent = m;
for (result = 1; exponent != 0; exponent >>= 1) {
if (exponent & 1) result *= base;
base *= base;
}
yield64(gen, result);
}
/* NOTREACHED */
}
 
ENTRY(enter_squares, powers(entry64, 2))
ENTRY(enter_cubes, powers(entry64, 3))
 
/*
* Generates the squares 0**2, 1**2, 2**2, ..., but removes the squares
* that equal the cubes 0**3, 1**3, 2**3, ....
*/
void
squares_without_cubes(struct gen64 *gen)
{
struct gen64 cubes, squares;
int64_t c, s;
 
gen64_init(&cubes, enter_cubes);
c = next64(&cubes);
 
gen64_init(&squares, enter_squares);
s = next64(&squares);
 
for (;;) {
if (c != s)
yield64(gen, s);
while (c <= s)
c = next64(&cubes);
s = next64(&squares);
}
/* NOTREACHED */
}
 
ENTRY(enter_squares_without_cubes, squares_without_cubes(entry64))
 
/*
* Look at the sequence of numbers that are squares but not cubes.
* Drop the first 20 numbers, then print the next 10 numbers.
*/
int
main()
{
struct gen64 gen;
int i;
 
gen64_init(&gen, enter_squares_without_cubes);
 
for (i = 0; i < 20; i++)
next64(&gen);
for (i = 0; i < 9; i++)
printf("%" PRId64 ", ", next64(&gen));
printf("%" PRId64 "\n", next64(&gen));
 
/*
* This program has no way to free the memory for all three
* coroutines. It can do co_delete(gen.giver) but then there
* would be no way to free the other two coroutines for squares
* and cubes.
*
* Here the program exits, to free the memory for the entire
* program.
*/
return 0;
}</lang>
 
One must download [http://byuu.org/programming/ libco] and give libco.c to the compiler.
 
<pre>$ libco=/home/kernigh/park/libco
$ cc -I$libco -o main main.c $libco/libco.c
$ ./main
529, 576, 625, 676, 784, 841, 900, 961, 1024, 1089</pre>
 
=={{header|E}}==
Line 53 ⟶ 203:
}
println()</lang>
 
=={{header|Go}}==
Generators can be implemented directly in Go by a channel fed by a goroutine.
Anonymous user