Commits

Shlomi Fish committed 15eeac0

Extract a top level subroutine and convert to slcm/sgcd.

  • Participants
  • Parent commits 058b15d

Comments (0)

Files changed (1)

File project-euler/466/euler-466-experimental-with-modulo-bit-vec.pl

     return $lcm;
 }
 
+# Small gcd (sgcd) and small lcm (slcm) that don't involve Math::GMP.
+
+sub sgcd
+{
+    my ($n, $m) = @_;
+
+    if ($m > $n)
+    {
+        ($n, $m) = ($m, $n);
+    }
+
+    while ($m > 0)
+    {
+        ($n, $m) = ($m, $n%$m);
+    }
+
+    return $n;
+}
+
+sub slcm
+{
+    my ($n, $m) = @_;
+
+    return ($n * $m / sgcd($n,$m));
+}
+
+sub count_mods_up_to_LIM
+{
+    my ($_r, $step, $l) = @_;
+
+    # Let's try to calculate in a smarter way.
+    my $recurse;
+
+    $recurse = sub {
+        my ($depth, $rows, $lcm, $lims) = @_;
+
+        if ($depth == @$_r)
+        {
+            my $sign = ($rows & 0x1 ? (-1) : 1);
+            # Including the modulo at zero.
+            foreach my $l (@$lims)
+            {
+                $l->[0] += $sign*(1 + $l->[1] / $lcm);
+            }
+        }
+        else
+        {
+            # If the lcm is greater, than the rest
+            # of the sum will be 0 because the lcm
+            # will only get larger and $l->[1] / $lcm
+            # would be always 0, so they will cancel
+            # each other.
+            my @new_lims = grep { $lcm <= $_->[1] } @$lims;
+
+            if (@new_lims)
+            {
+                $recurse->(
+                    $depth+1,
+                    $rows,
+                    $lcm,
+                    \@new_lims,
+                );
+                $recurse->(
+                    $depth+1,
+                    $rows+1,
+                    slcm($lcm, $_r->[$depth]),
+                    \@new_lims,
+                );
+            }
+        }
+
+        return;
+    };
+
+    my @LIM = ( map { [0,$_*$step] } @$l );
+
+    $recurse->(0, 0, $step, \@LIM);
+
+    return [map { $_->[0] } @LIM];
+}
+
 my $DEBUG = 1;
 
 use Inline (C => <<'EOF',
 
         foreach my $next_row ($row_idx+1 .. $MIN)
         {
-            my $step = 0+(''.lcm($row_idx, $next_row));
+            my $step = slcm($row_idx, $next_row);
             my $start_prod = ($start_i_prod / $step) * $step;
             if ($start_i_prod % $step)
             {
                     # - inclusive. So $_count_mods_up_to_LIM->(0) can be
                     # non-zero.
 
-                    # Put the largest ones first.
                     my $_count_mods_up_to_LIM;
 
                     {
+                        # Put the largest ones first.
                         my @_r = reverse@aft_rows;
 
                         $_count_mods_up_to_LIM  = sub {
-
-                            my $l = shift;
-
-                            # Let's try to calculate in a smarter way.
-                            my $recurse;
-
-                            $recurse = sub {
-                                my ($depth, $rows, $lcm, $lims) = @_;
-
-                                if ($depth == @aft_rows)
-                                {
-                                    my $sign = ($rows & 0x1 ? (-1) : 1);
-                                    # Including the modulo at zero.
-                                    foreach my $l (@$lims)
-                                    {
-                                        $l->[0] += $sign*(1 + $l->[1] / $lcm);
-                                    }
-                                }
-                                else
-                                {
-                                    # If the lcm is greater, than the rest
-                                    # of the sum will be 0 because the lcm
-                                    # will only get larger and $l->[1] / $lcm
-                                    # would be always 0, so they will cancel
-                                    # each other.
-                                    my @new_lims = grep { $lcm <= $_->[1] } @$lims;
-
-                                    if (@new_lims)
-                                    {
-                                        $recurse->(
-                                            $depth+1,
-                                            $rows,
-                                            $lcm,
-                                            \@new_lims,
-                                        );
-                                        $recurse->(
-                                            $depth+1,
-                                            $rows+1,
-                                            lcm($lcm, $_r[$depth]),
-                                            \@new_lims,
-                                        );
-                                    }
-                                }
-
-                                return;
-                            };
-
-                            my @LIM = ( map { [0,$_*$step] } @$l );
-
-                            $recurse->(0, 0, $step, \@LIM);
-
-                            return [map { $_->[0] } @LIM];
+                            return count_mods_up_to_LIM(\@_r, $step, shift);
                         };
                     }
 
         my_test(64, 64, 1263);
     }
 
-    if (1 and !$DEBUG)
+    if (0 and !$DEBUG)
     {
         my_test(32, (('1'.('0'x15))+0), 13826382602124302);
     }
 
-    if (0 and !$DEBUG)
+    if (1 and !$DEBUG)
     {
         my $WRONG_RESULT = 100;
         my_test(64, (('1'.('0' x 16))+0), $WRONG_RESULT);