$ include "seed7_05.s7i";
include "bigint.s7i";
const type: cycle is new struct
var bigInteger: the_attractor is 0_;
var bigInteger: the_initiator is 0_;
var bigInteger: the_gcd is 0_;
var bigInteger: the_length is 0_;
end struct;
var array cycle: cycle_stats is 0 times cycle.value;
var set of bigInteger: att is (set of bigInteger).EMPTY_SET;
const func bigInteger: collatz (in bigInteger: n, in bigInteger: C) is func
result
var bigInteger: cn is 0_;
local
var integer: LSB is 0;
begin
cn := n * 3_ + C;
LSB := lowestSetBit(cn);
cn >>:= LSB;
end func;
const func bigInteger: attractor (in bigInteger: n, in bigInteger: C, in bigInteger: seed) is func
result
var bigInteger: attractor is 0_;
local
var bigInteger: cycle_length is 0_;
var bigInteger: entry_point is 0_;
var bigInteger: cycle_gcd is 0_;
var bigInteger: a is 0_;
var cycle: attractor_stats is cycle.value;
begin
attractor := n;
entry_point := n;
a := n;
repeat
if a < attractor then
attractor := a;
end if;
a := collatz(a,C);
cycle_length +:= 1_;
if cycle_gcd = 0_ then
cycle_gcd := gcd(a,entry_point);
end if;
until a = entry_point;
if attractor not in att then
incl(att,attractor);
attractor_stats.the_attractor := attractor;
attractor_stats.the_initiator := seed;
attractor_stats.the_gcd := cycle_gcd;
attractor_stats.the_length := cycle_length;
cycle_stats &:= [](attractor_stats);
end if;
end func;
const func bigInteger: brent (in bigInteger: n, in bigInteger: C) is func
result
var bigInteger: tortoise is 0_;
local
var bigInteger: power is 1_;
var bigInteger: lam is 1_;
var bigInteger: hare is 0_;
var bigInteger: i is 1_;
begin
tortoise := n;
hare := collatz(n,C);
while tortoise <> hare do
if power = lam then
tortoise := hare;
power *:= 2_;
lam := 0_;
end if;
hare := collatz(hare,C);
lam +:= 1_;
end while;
tortoise := n;
hare := n;
for i range 1_ to lam do
hare := collatz(hare,C);
end for;
while tortoise <> hare do
tortoise := collatz(tortoise,C);
hare := collatz(hare,C);
end while;
end func;
const proc: main is func
local
var bigInteger: n is 0_;
var bigInteger: e is 0_;
var bigInteger: C is 0_;
var bigInteger: o is 0_;
var cycle: a is cycle.value;
var bigInteger: seed is 0_;
begin
if (length(argv(PROGRAM)) < 4) then
writeln();
writeln("ABORTING -- requires 4 parameters");
writeln();
writeln(" usage: ecd010 N E C O");
writeln(" N - start of seed range (must be odd)");
writeln(" E - end of seed range");
writeln(" C - C of the 3n+C Collatz function");
writeln(" O - options none as of this version (enter 0)");
writeln();
writeln("EXAMPLE: $ ./ecd010 1 40 16777213 0");
writeln(" | | | |");
writeln(" | | | no options");
writeln(" | | use 3n+16777213");
writeln(" | up to 40");
writeln(" start @ 1");
writeln();
writeln("EXAMPLE OUTPUT: 16777213 16777213 16777213 1");
writeln(" 1 1 1 1");
writeln(" 143 3 1 254252");
writeln(" 29 5 1 254241");
writeln(" 119 7 1 254214");
writeln(" | | | |");
writeln(" | | | length of cycle");
writeln(" | | gcd of cycle");
writeln(" | seed that led to this cycle");
writeln(" attractor (smallest node in cycle)");
writeln();
writeln("C is always added to the attractor list even if outside the requested seed range");
writeln("because EVERY 3n+C has C as an attractor whose cycle stats are always C C C 1");
writeln();
exit(PROGRAM);
end if;
n := bigInteger parse (argv(PROGRAM)[1]);
e := bigInteger parse (argv(PROGRAM)[2]);
C := bigInteger parse (argv(PROGRAM)[3]);
seed := n;
incl(att,C);
a.the_attractor := C;
a.the_initiator := C;
a.the_gcd := C;
a.the_length := 1_;
cycle_stats &:= [](a);
while seed < e do
if seed <> C then
o := brent(seed,C);
o := attractor(o,C,seed);
end if;
seed +:= 2_;
end while;
for a range cycle_stats do
write(a.the_attractor);
write("\t");
write(a.the_initiator);
write("\t");
write(a.the_gcd);
write("\t");
writeln(a.the_length);
end for;
end func;