I have the following working code:
largest_prime=1
for number_under_test in {1..100}
do
is_prime=true
factors=''
for ((divider = 2; divider < number_under_test-1; divider++));
do
remainder=$(($number_under_test % $divider))
[ $remainder == 0 ] && [ is_prime ] && is_prime=false && factors+=$divider' '
done
[ $is_prime == true ] && echo "${number_under_test} is prime!" || echo "${number_under_test} is NOT prime (factors= $factors)" [ $is_prime == true ] && largest_prime=$number_under_test
done
printf "\nLargest Prime= $largest_prime\n"
This code runs quickly is 0.194 seconds. However I found the && is_prime= false
a bit hard to read and it could look (to the untrained eye) as if it was being tested rather than being set which is what it does.
So I tried changed the &&
into an if...then
and this works - but is 75 times slower at 14.48 seconds. It's most noticeable on the higher numbers.
largest_prime=1
for number_under_test in {1..100}
do
is_prime=true
factors=''
for ((divider = 2; divider < number_under_test-1; divider++));
do
remainder=$(($number_under_test % $divider))
if ([ $remainder == 0 ] && [ $is_prime == true ]); then
is_prime=false
factors+=$divider' '
fi
done
[ $is_prime == true ] && echo "${number_under_test} is prime!" || echo "${number_under_test} is NOT prime (factors= $factors)" [ $is_prime == true ] && largest_prime=$number_under_test
done
printf "\nLargest Prime= $largest_prime\n"
Is there any was to have the clarity of the block without the slowness?
Update (1/4/2015 10:40am EST)
Great feedback! I am now using the following. Any other feedback ?
largest_prime=1
separator=' '
for number_under_test in {1..100}; {
is_prime=true
factors=''
for ((divider = 2; divider < (number_under_test/2)+1; divider++)) {
remainder=$(($number_under_test % $divider))
if [ $remainder == 0 ]; then
is_prime=false
factors+=$divider' '
fi
}
if $is_prime; then
printf "\n${number_under_test} IS prime\n\n"
largest_prime=$number_under_test
else
printf "${number_under_test} is NOT prime, factors are: "
printf "$factors\n"
fi
}
printf "\nLargest Prime= $largest_prime\n"
Largest Prime= 100
on my computer. – Giulio Muscarello Jan 03 '15 at 18:09number_under_test/2
instead of up tonumber_under_test-1
: No factor of a number n is greater than n/2, so you will still find all factors for non-prime numbers by doing this. (Also if you were only interested in testing for primeness, it would be sufficient to iterate up to sqrt(n), but Bash doesn't have a built-in function to compute square roots anyway.) – Malte Skoruppa Jan 04 '15 at 00:42(number_under_test/2)+1
to allow for that – Michael Durrant Jan 04 '15 at 14:36{}
are not really needed after thethen
clause because thethen
already serves as a grouping operator (along withelif
,else
, orfi
). In fact, in some shells, you could write, for example,for i in 1 2 3; { echo $i; }
with nodo
ordone
. – Jonathan Leffler Jan 04 '15 at 15:27unset IFS
.if $is_prime
will fail unless$is_prime
evals to a word. If it is split for any reason it will fail. You also have the problem of needing to generate your entire parameter set before you can do even a single calculation. It is very inefficient and the whole{1..100}
block must reside in memory for the duration. – mikeserv Jan 04 '15 at 20:26if [ $remainder == 0 ]
-- this is an arithmetic test, so use an arithmetic expression:if (( $remainder == 0 ))
-- or remove the temp variable altogether:if (( $number_under_test % $divider == 0 ))
. You don't actually use the$separator
variable anywhere – glenn jackman Jan 05 '15 at 14:35printf
without a format specifier. If one of your variables happens to contain a%
, you'll get an error. – glenn jackman Jan 05 '15 at 14:43(( $var ))
is definitely not a safe thing to do. Rather(( var ))
should be preferred. But((...))
is probably not a good way to go, anyway. – mikeserv Jan 05 '15 at 17:10[ "$((...))" -ne 0 ]
or evenmath() { return "$((!($*)))"; }
but is far less portable. You might as well use syntax that will work everywhere rather limiting the application of what you do if the practical difference amounts only to typing a few characters. – mikeserv Jan 05 '15 at 17:44bash
andzsh
at least even(( var ))
is still an unsafe thing to do. I think both of those shells will still wind up evaling the contents as a math statement rather than an integer regardless of whether you$expand
it first or not. You could explicitlytypeset
it first, I suppose, to guard against that. But if you do so, then its contents are no longer questionable. – mikeserv Jan 05 '15 at 18:04