aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Rifkin <ian.p.rifkin@gmail.com>2020-02-25 21:35:56 -0500
committerIan Rifkin <ian.p.rifkin@gmail.com>2020-02-25 21:35:56 -0500
commited38af056a3b29ce9d3811605b07c23e16d0d5f6 (patch)
tree024c1d45d886230aadaafcabb2db2bd62c3ef9b7
parentb794f36b29be553e1b6dc1e790c5d0bf331a9bc3 (diff)
downloadperlweeklychallenge-club-ed38af056a3b29ce9d3811605b07c23e16d0d5f6.tar.gz
perlweeklychallenge-club-ed38af056a3b29ce9d3811605b07c23e16d0d5f6.tar.bz2
perlweeklychallenge-club-ed38af056a3b29ce9d3811605b07c23e16d0d5f6.zip
adding challenge 1
-rw-r--r--challenge-049/ianrifkin/perl/ch-1.pl58
1 files changed, 58 insertions, 0 deletions
diff --git a/challenge-049/ianrifkin/perl/ch-1.pl b/challenge-049/ianrifkin/perl/ch-1.pl
new file mode 100644
index 0000000000..99e2b30dcc
--- /dev/null
+++ b/challenge-049/ianrifkin/perl/ch-1.pl
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+use strict;
+use Scalar::Util::Numeric qw(isint);
+use Math::BigInt;
+use Math::BigFloat;
+
+#### Smallest Multiple
+#### Write a script to accept a positive number as command line argument and
+#### print the smallest multiple of the given number consists of digits 0 and 1.
+#### Solution by ianrifkin
+
+#### Assumption 1: the smallest multiple will ONLY have digits 0 and 1
+#### Assumption 2: Multiples are at least double the input (e.g. the multiple of 100 is 1000 and not 100)
+
+my $input = $ARGV[0];
+
+die("Input must be a positive number") unless $input > 0;
+
+my $i = 2;
+my $output = undef;
+
+
+# You could loop through every number and check if it's correct
+# For smaller answers like when $input = 2, or 5, or 100 it's quick
+# But when $input is 9 you can see how this starts to take too long to find the answer
+# and input = 99 is way too long to wait.
+
+# Instead b/c of assumption #1 we know that the answer will be
+# only 0's and 1's we can do math using only binary numbers
+
+# subroutine taken from Perl Cookbook to convert decimals to binaries
+sub dec2bin {
+ my $str = unpack("B32", pack("N", shift));
+ $str =~ s/^0+(?=\d)//; # otherwise you'll get leading zeros
+ return $str;
+}
+
+# for example when input = 9 in the first commented out method
+# it would take 1011111110 loops to get to 1011111111
+# But in this method it only takes 766 loops.
+
+while ($output == undef) {
+ my $bin_i = dec2bin($i);
+ $i++ and next unless $bin_i =~ /^1[1]*[0]+[0-1]*$/;
+ my $test = Math::BigFloat->new($bin_i);
+ $test->bdiv($input);
+ $output = $bin_i if $test == $test->as_int() and $input != $bin_i;
+ $i++;
+}
+
+print "\n\nThe smallest multiple of $input with only digits 0 and 1 is: $output\n\n";
+
+# Note on BigFloat
+# My first attempt was to Scalar::Util::Numeric (or INT, POSIX or ROUND) to check
+# if binary/input is an int e.g. check $test == isint($test)
+# But this would return incorrect results when inputting a number like 99 because
+# it was incorrectly rounding $test (too many digits?)
+# Using Math::BigFloat instead solves this problem but it's a major performance hit.