4

I have 50,000 numbers (that could range from 0 to 50,000). And I need (product of these numbers) MOD 1000000007. The following code is so trivial, there should be other ways. Heard about "Divide and conquer" techniques, but have no idea how to implement.

$ans *= ( $_ % 1000000007 ) foreach @array;
$ans %= 1000000007;

Please suggest.

Igor
  • 26,650
  • 27
  • 89
  • 114
trinity
  • 10,394
  • 15
  • 49
  • 67
  • 3
    If every number in `@array` is < 50,000, then `$_ % 1000000007` will not change anything, since that is calculated before the multiplication. – TLP Jan 07 '12 at 12:35

3 Answers3

7

The result of $num % 1000000007 will always be $num for all values less than 1000000007. So if all values in @array are within the range 0 .. 50,000, such a calculation is redundant. You would have to do two steps, and not use the *= operator:

$ans = ($ans % 1000000007) * $_ for @array;

Word of caution, though. For any non-prime modulo there's always the risk that your modulo operation results in zero, which will of course cause the entire multiplication to produce zero. I think you've already thought of this, since 1000000007 seems to be a prime number, but I'll just mention it anyway.

ETA: Reusing intermediate products:

for (@array) {
    $ans *= $_;
    print "Before mod: $ans\n";
    $ans %= 1000000007;
    print "After mod : $ans\n";
}

Note that you do not need to compound the operators here.

TLP
  • 66,756
  • 10
  • 92
  • 149
  • Thanks for pointing the redundancy, Is there a way we can reuse intermediate multiplication results ??.. – trinity Jan 07 '12 at 15:51
  • @trinity Reuse? Well, with a postfix loop, that'll get tricky, and frankly, not worth it. I'll add an example. – TLP Jan 07 '12 at 16:00
1

Although you do $_ % 1000000007 on every number from your array, your $ans can get very large until you finally do $ans %= 1000000007 after the look.

To correct this i suggest the following:

foreach my $number (@array)
{
  $ans *= ($number % 1000000007);
  $ans %= 1000000007;
}
NiklasMM
  • 2,895
  • 2
  • 22
  • 26
  • 3
    You can omit `($number % 1000000007)`, and do just `$ans *= $number`. The numbers are up to 50,000 (and even for larger numbers, there's no reason to do % twice). – ugoren Jan 07 '12 at 12:55
1

If computational reuse is important/expected (as mentioned in a comment to TLP's answer), then memoizing the function will help speed up by effectively remembering previously calculated results.

See Chapter 3: Caching and Memoization in Higher-Order Perl

Zaid
  • 36,680
  • 16
  • 86
  • 155