Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add a working solution of #463.
  • Loading branch information
shlomif committed Jun 15, 2016
1 parent 00f090f commit 0838dc2
Showing 1 changed file with 135 additions and 4 deletions.
139 changes: 135 additions & 4 deletions categories/euler/prob463-shlomif.p6
@@ -1,5 +1,10 @@
use v6;

# Dedicated to the memory of Christina Grimmie (
# https://en.wikipedia.org/wiki/Christina_Grimmie ), see:
# https://www.youtube.com/watch?v=kYX8sjIzjGw .
# -- shlomif

class Poly
{
has $.mult;
Expand Down Expand Up @@ -104,10 +109,136 @@ sub lookup($mult)
return @($ret).map({ .mult });
}

my $mult = 4;
while (1)
if (False)
{
my $mult = 4;
while (1)
{
say lookup($mult);
$mult +<= 1;
}
}

my $MOD = 1_000_000_000;

sub _cache(%h, $key, $promise)
{
my $ret = %h{$key};

if (!defined($ret))
{
$ret = ($promise.() % $MOD);
%h{$key} = $ret;
}

return $ret;
}

my %f_cache;

sub f_mod($n)
{
if ($n < 1)
{
die "Foo";
}

return _cache(%f_cache, $n, sub {
if ($n == 1)
{
return 1;
}
elsif ($n == 3)
{
return 3;
}
elsif (($n +& 1) == 0)
{
return f_mod($n +> 1);
}
elsif (($n +& 3) == 1)
{
return (2 * f_mod(($n +> 1) + 1) - f_mod($n +> 2));
}
else
{
return (3 * f_mod(($n +> 1)) - 2 * f_mod($n +> 2));
}
}
);
}

sub s_bruteforce
{
say lookup($mult);
$mult +<= 1;
my ($n) = @_;

my $s = 0;

for 1 .. $n -> $i
{
($s += f_mod($i)) %= $MOD;
}

return $s;
}

sub s_smart($start, $end)
{
state %s_cache;

# say "s->e : $start->$end";
return _cache(%s_cache, "$start|$end", sub {
if ($start > $end)
{
return 0;
}
if ($start == $end)
{
return f_mod($start);
}
if ($end <= 8)
{
return s_bruteforce($end) - s_bruteforce($start - 1);
}
if (($start +& 0b11) != 0)
{
return (f_mod($start) + s_smart($start+1, $end));
}
if (($end +& 0b11) != 0b11)
{
return (f_mod($end) + s_smart($start, $end-1));
}
my $power2 = ((($start +& ($start-1)) != 0) ?? 1+(($start-1)+^$start) !! $start);
my $new_end = $start + $power2 - 1;
while ($new_end > $end)
{
$new_end = $start + ($power2 +>= 1) - 1;
}
my @c = lookup($power2);
my $m = $start / $power2;
return (@c[0] * f_mod($m*2+1) + @c[1] * f_mod($m) + s_smart($new_end+1, $end));
},
);
}

if (False)
{
my $want = 0;
for 1 .. 100_000 -> $n
{
if ($n % 1_000 == 0)
{
say "Reached n=$n";
}
($want += f_mod($n)) %= $MOD;
my $have = s_smart(1, $n);
if ($want != $have)
{
die "want=$want have=$have n=$n!";
}
}
}

{
say "S(3 ** 37) = ", s_smart(1, 3 ** 37);
}

4 comments on commit 0838dc2

@coke
Copy link
Contributor

@coke coke commented on 0838dc2 Jun 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that parens are not required on perl 6 ifs.

@paultcochrane
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have removed the parens on the ifs.

@shlomif: just wondering what the if False blocks are for. Is it ok to remove them, or should I maybe add a debug flag so that one can run them if desired?

@shlomif
Copy link
Contributor Author

@shlomif shlomif commented on 0838dc2 Sep 5, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paultcochrane : the if False blocks were used for debugging. Please add a debug flag for them.

@paultcochrane
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shlomif thanks for your quick reply! Debug flag added.

Please sign in to comment.