Finding all divisors of an integer
chiburashka
created: 2004-07-03 09:53:31
is there a fast way to tell all the numbers that a spesific number divides on without leftovers (like for the spesific number "20" it divedes on 1,2,4,5,10,20 and stays as an integer) ? How to find those "1,2,4,5,10,20" in the fastest way ?

that's my code :

#!/usr/bin/perl
use Math::BigInt;

print "Enter the big number : ";
$x = readline(*STDIN);
print "Enter the little number : ";
$y = readline(*STDIN);
$z = $x - $y;
$i = $z;
@all = '';
$j = 0;
system cls;

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(time);

while ($i ne 0) {
$t = $z / $i;
$k = Math::BigInt->new($t);
$k = $k->is_int();
if ($k eq "1") {$j++; $all[$j] = "$t\n";}
$i--; print "$i\n";
}
($sec1,$min1,$hour1,$mday,$mon,$year,$wday,$yday) = gmtime(time);

$data="Dis.txt";
open(DAT, $data) || die("Could not open file!");
@al=;
@al = @all;
open(DAT,">$data") || die("Cannot Open File");
print DAT @al; 
close(DAT);

print "@all It took ", $min1 - $min, " minuts!\n";
$w = readline(*STDIN);

now how to make it find those numbers FASTER ?

20040705 Edit by [castaway]: Changed title from 'Didision'

Re: Finding all divisors of an integer
created: 2004-07-03 10:01:59

For small numbers, this should be straightforward ...

@divisors = grep { $number % $_ == 0 } 1 .. $number;

I would not worry about optimizing this, unless you need it for very many or very big numbers ... but then it would be something like this:

# First, the lower half of the divisors:
@divisors = grep { $number % $_ == 0 } 1 .. sqrt($number);
# Then, the upper half:
push @divisors, map {$number == $_*$_ ? () : $number/$_} reverse @divisors;

(Sorry, I missed the Math::BigInt stuff ... but I guess the algorithm above can be adapted to that case as well?)

Update: Most of my code could benefit from comments. I added comments to the optimized version. Never code as if the guy who ends up maintaining your code can always maintain a proper caffeine intake.

print "Just another Perl ${\(trickster and hacker)},"
The Sidhekin proves Sidhe did it!

Re^2: Finding all divisors of an integer
created: 2004-07-03 10:09:56
and how will i know how many numbers are in @divisors in the second case ?
Re^3: Finding all divisors of an integer
created: 2004-07-03 10:27:46

and how will i know how many numbers are in @divisors in the second case ?

Well, this is basic Perl. To quote perldata:

If you evaluate an array in scalar context, it returns the length of the array.

So, scalar(@divisors) returns the number of divisors.

print "Just another Perl ${\(trickster and hacker)},"
The Sidhekin proves Sidhe did it!

Re^3: Finding all divisors of an integer
created: 2004-07-07 18:13:41
how?
Re^2: Finding all divisors of an integer
created: 2004-07-03 10:10:30
Sidhekin,
I would not worry about optimizing this, unless you need it for very many or very big numbers
Indeed, the node was updated after you (and I) already started posting. I would say that you only need to go to $number / 2 though.

@divisors = grep { $number % $_ == 0 } 1 .. sqrt($number);
I think you are thinking of prime factorization here. You can stop there to determine primeness but not to determine all factors.

Cheers - L~R

People should not be allowed to touch keyboards early in the morning (weekend) without proper caffeine intake. I completely missed the push in the second line of code
Re^3: Finding all divisors of an integer
created: 2004-07-03 10:13:03
i simply want to make each $divisors[$i] = "$divisors[$i]\n";

so i need to know this $i...

Re^4: Finding all divisors of an integer
created: 2004-07-04 01:52:59
No, you don't need to know how many there are.
$_.="\n" for @divisors;
# or
@divisors = map "$_\n", @divisors;
# or
for my $divisor (@divisors) {
    $divisor = "$divisor\n";
}
# etc.
Re^3: Finding all divisors of an integer
created: 2004-07-03 10:16:44

@divisors = grep { $number % $_ == 0 } 1 .. sqrt($number);
I think you are thinking of prime factorization here. You can stop there to determine primeness but not to determine all factors.

You somehow miss the second line of my optimized solution. It adds the other half of the divisors. :-)

push @divisors, map {$number == $_*$_ ? () : $number/$_} reverse @divisors;

For every divisor above the square root, there is a corresponding divisor below the square root. Symmetrical optimization. :-)

print "Just another Perl ${\(trickster and hacker)},"
The Sidhekin proves Sidhe did it!

Re^4: Finding all divisors of an integer
created: 2004-07-03 10:18:38
so u mean that there is "int(sqrt($number))" indexes in @divisors ?
Re^5: Finding all divisors of an integer
created: 2004-07-07 18:13:25
what say?
Re: Finding all divisors of an integer
created: 2004-07-03 10:05:13
[chiburashka],
My solution will likely not win the "fastest way" solution. There are likely [http://www.cpan.org|CPAN] modules that do this as well. Usually when someone wants the fastest way to do something - they are taking the wrong approach or using the wrong language. Perhaps if you don't get the answers you like you should expand on the overall picture.
#!/usr/bin/perl
use strict;
use warnings;

my @factors = Factor_It( 20 );
print "$_\n" for @factors;

sub Factor_It {
    my $number = shift;
    my @factors;
    for ( 2 .. int $number / 2 ) {        
        push @factors, $_ unless $number % $_;
    }
    return (1, @factors, $number);
}
Of course, you will also want to add some checks to ensure your input is a positive whole integer greater than 1.

Cheers - [Limbic~Region|L~R]

It looks like you updated your node after you posted it with the BigInt stuff - probably want a CPAN module with XS code. You can avoid checking even numbers if it is not evenly divisible by 2 on the first check
Re: Finding all divisors of an integer
created: 2004-07-03 10:06:23
It's already answered, so my solution is obsolete.
#!/usr/bin/perl

use strict;
use warnings;

chomp(my $is = shift);
for (1 .. $is) {
  print "$_ " if ($is % $_ == 0);
}
print "\n";
Re: Finding all divisors of an integer
created: 2004-07-03 10:08:43
The process you are asking about is called factorization in mathematics. Depending on what you call fast, there may not be a really fast method for factoring large numbers.
Re: Finding all divisors of an integer
created: 2004-07-03 10:08:45
Crocodil Gena

This sounds like a homework problem. Yet nonetheless, let me give a shot at answering your question. Basically what you are asking for is an algorithm that finds the smallest prime number a given number is divisible by (except for the multiplicative identity). So, in your case, the smallest prime that 20 is divisible by is 2, giving your a remainder of 10. The smallest prime 10 is divisible by is, again, 2, giving you a remainder of 5. Five, in itself is prime, so you're done.

So, 20 is made up of 2,2,5, and of course the multiplicative identity. Multiplying together the different combinations of the found primes, gives you the factors you were asked to find.

Re^2: Finding all divisors of an integer
created: 2004-07-04 12:25:07

That's not at all the question that is being asked, and has nothing to do with primes. OP is asking for factorization all factors of a number.

Re^3: Finding all divisors of an integer
created: 2004-07-05 12:40:51
This algorithm finds all factors of a number!
Re: Finding all divisors of an integer
created: 2004-07-03 11:36:53

Only numbers up to the square root of the large number need to be checked - not half.

Re: Finding all divisors of an integer
created: 2004-07-04 04:29:30
Here's an implementation of [gri6507]'s suggestion (using ordinary perl integers, not bigints):
use warnings;
use strict;
use integer;

$|=1;
print "Enter number: ";
chomp(my $x = );
die "That's not my kind of number!" if $x=~/\D/ || $x/1 ne $x;

if ($x <= 1) { print "$x\n"; exit }

# get prime factors
my %fact;
my $fact = 2;
do {
    ++$fact while $x/$fact*$fact != $x;
    ++$fact{$fact};
    $x /= $fact;
} while ($x > 1);

# apply all combinations
my @fact = 1;
while (($fact,my $count) = each %fact) {
    my $index;
    @fact = map $_ * $fact**(++$index/@fact % ($count+1)),
                (@fact) x ($count+1);
}
print "@{[sort {$a<=>$b} @fact]}\n";
Re: Finding all divisors of an integer
created: 2004-07-07 18:14:14
This node was taken out by the NodeReaper on Wed Jul 7 18:47:17 2004 (EST)
Reason: Elian Empty

For more information on this node visit: this

perlmonks.org content © perlmonks.org and Anonymous Monk, chiburashka, gaal, gri6507, Limbic~Region, neniro, NodeReaper, pbeckingham, Sidhekin, ysth

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03