Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Re^3: OT: Finding Factor Closest To Square Root

by BrowserUk (Patriarch)
on Feb 19, 2005 at 00:32 UTC ( [id://432584]=note: print w/replies, xml ) Need Help??


in reply to Re^2: OT: Finding Factor Closest To Square Root
in thread OT: Finding Factor Closest To Square Root

One testcase was never going to hack it. I should have thought of your method, but I was too busy trying to figure out why CPAN would install M::B::F.


Examine what is said, not who speaks.
Silence betokens consent.
Love the truth but pardon error.

Replies are listed 'Best First'.
Re^4: OT: Finding Factor Closest To Square Root
by Roy Johnson (Monsignor) on Feb 19, 2005 at 00:48 UTC
    Mine isn't perfect, either. Try 2,2,2,7,19,19, for example. I'm pretty sure the problem requires an exhaustive search of all combinations.

    Caution: Contents may have been coded under pressure.

      Yeah! I'm reaching a similar conclusion..now if only I could work out to use Algorithm::Loops, it'd be done in a trice :)


      Examine what is said, not who speaks.
      Silence betokens consent.
      Love the truth but pardon error.
        Here's a recursive solution to find the closest set of factors to a target (with wrapper script). I think it's solid.
        use strict; use warnings; use List::Util qw[ reduce ]; my @pfs = ( 2,3,3,3,7, 997 ); my $num = reduce { $a * $b } @pfs; my $root = sqrt $num; print "N=$num, R=$root\n"; sub closest { # Args are target and factor-list my ($target, $car, @cdr) = @_; @cdr or return $car; reduce { abs($target - $a) < abs($target - $b) ? $a : $b } ($car*closest($target/$car, @cdr), closest($target, @cdr), $c +ar); } print closest($root, @pfs), "\n";

        Caution: Contents may have been coded under pressure.
        BrowserUk,
        The following code demonstrates that this is not actually true:
        • If a subset has been seen before, it is skipped prior to determining the product of the subset
        • If a subset is the start of a progression of subsets previously seen, the entire progression is skipped
        • If a factor is determined to be larger than the sqrt, determining if it is the closest is skipped
        Unfortunately, I do not know if this is the fastest implementation. I have several variations ranging from bitstrings to avoiding push/slice. The trouble is that I have found an apparent bug in Math::Pari so I am not sure which solution should be fastest. The bug only seems to manifest itself when I add the sqrt() code. To see the bug for yourself using 24777695232, add print "$_\n" for @factor; right after the array is created. To see it go away, comment out the $sqrt definition and change the return statement to return $f.

        Cheers - L~R

        Here's an Algorithm::Loops solution, then, based on lidden's nifty solution:
        use strict; use warnings; use List::Util qw[ reduce ]; use Algorithm::Loops 'NextPermuteNum'; sub closest{ my $exact = sqrt(shift); my $best = 1; do { my $guess = 1; for (@_) { $guess *= $_; $best = $guess if (abs($exact - $guess) < abs($exact - $be +st)); last if $guess > $exact; } } while NextPermuteNum(@_); $best; } my @pfs = (2,2,3,3,5,5,7); # Compute product of factors our ($a, $b); my $num = reduce { $a * $b } @pfs; my $root = sqrt $num; print "N=$num, R=$root\n"; print closest($num, @pfs), "\n";

        Caution: Contents may have been coded under pressure.
      Roy Johnson,
      I am pretty sure that all combinations need to be considered initially as you can see by my contributions elsewhere in this thread. It is possible to short-circuit early in some cases though, which may be a significant improvement. For instance - here are some ideas:
      • Prior to determining the product of each combination, you can abort if you have already seen this combination
      • When determining the product of each combination, you can abort if the value is greater than the sqrt
      • If combinations are gathered left to right, once you have determined that the product of a given combination is greater than the sqrt() all future combinations that include this combination can be skipped
      I have only chosen to implement the first 1 in my Perl code. This is because my combinations aren't gathered left to right. I will see if I can't modify the code to take advantage of all 3 of these short cuts.

      Cheers - L~R

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://432584]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (3)
As of 2024-04-24 18:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found