Skip to content

Commit a1a3b2f

Browse files
authored
Bash/solution_1: Pure bash & reduce code duplication (PlummersSoftwareLLC#895)
1 parent ca73a8d commit a1a3b2f

File tree

6 files changed

+155
-426
lines changed

6 files changed

+155
-426
lines changed

PrimeBash/solution_1/Dockerfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
FROM ubuntu:22.04
44

55
WORKDIR /opt/app
6-
COPY *.sh ./
7-
6+
COPY *.sh *.common ./
7+
88
ENTRYPOINT [ "./run.sh" ]

PrimeBash/solution_1/PrimeBash.common

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#
2+
# Common routines for a simple prome sieve written in pure bash.
3+
#
4+
5+
# rbergen -- changed number for 10 from 1 to 4
6+
readonly -A primeCounts=(
7+
[10]=4
8+
[100]=25
9+
[1000]=168
10+
[10000]=1229
11+
[100000]=9592
12+
[1000000]=78498
13+
[10000000]=664579
14+
[100000000]=576145
15+
)
16+
17+
declare sieveSize=0
18+
declare -A bitArray=()
19+
# rbergen: changed runtime to drag-race default
20+
readonly RUNTIME_SEC=5
21+
22+
function sqrt {
23+
# integer square root using binary search (lilweege)
24+
local -n lo=$1 # Output
25+
lo=1
26+
hi=$2
27+
mid=0
28+
while ((lo<=hi)); do
29+
((mid=(lo+hi)/2))
30+
if [[ $((mid*mid)) -le $2 ]]; then
31+
((lo=mid+1))
32+
else
33+
((hi=mid-1))
34+
fi
35+
done
36+
((--lo))
37+
}
38+
39+
function initGlobals {
40+
sieveSize=$1
41+
}
42+
43+
function emptyBitArray {
44+
bitArray=()
45+
}
46+
47+
function validateResults {
48+
local result=$1
49+
(( primeCounts[\$sieveSize] == result ))
50+
}
51+
52+
function countPrimes {
53+
local i count=$((sieveSize >= 2))
54+
for ((i=3; i < sieveSize; i++)); do
55+
if getBit "$i"; then
56+
((++count))
57+
fi
58+
done
59+
echo "$count"
60+
}
61+
62+
function getBit {
63+
# Return failure if even if bitArray is set (determined composite)
64+
# Return success if known prime
65+
(( $1 & 1 && !bitArray[\$1] ))
66+
}
67+
68+
function printResults {
69+
local showresults dur_usec avg_dur_usec dur_str avg_dur_str passes count valid
70+
local showresults="$1"
71+
local dur_usec="$2"
72+
local passes="$3"
73+
local name="$4"
74+
75+
# create duration strings from millisecond duration time
76+
avg_dur_usec=$((dur_usec/passes))
77+
printf -v dur_str "%d.%06d" \
78+
$((dur_usec/1000000)) $((dur_usec%1000000))
79+
printf -v avg_dur_str "%d.%06d" \
80+
$((avg_dur_usec/1000000)) $((avg_dur_usec%1000000))
81+
82+
# create validity string
83+
if validateResults "$(countPrimes)"; then
84+
valid="True"
85+
else
86+
valid="False"
87+
fi
88+
89+
if ((showresults)); then
90+
printf "2, "
91+
fi
92+
93+
count=$((sieveSize >= 2))
94+
for ((num=3; num<sieveSize; num+=2)); do
95+
if getBit "$num"; then
96+
if ((showresults)); then
97+
printf "%s, " "$num"
98+
fi
99+
((count++))
100+
fi
101+
done
102+
103+
if ((count != $(countPrimes))); then
104+
echo "Internal: Print Results Counted Incorrectly..." >&2
105+
exit 1
106+
fi
107+
printf "\nPasses: %s, Time: %s, Avg: %s, Limit: %s, Count: %s, Valid: %s\n" \
108+
"$passes" "$dur_str" "$avg_dur_str" "$sieveSize" "$count" "$valid"
109+
110+
# rbergen: added drag-race format output
111+
printf "%s;%s;%s;1;algorithm=base,faithful=no\n" "$name" "$passes" "$dur_str"
112+
}
113+
114+
function main {
115+
export LC_ALL=C
116+
local passes=0 tStart tRun name="$1"
117+
118+
# Keep /dev/null handle open so we don't pay for opening it later
119+
exec 3>/dev/null
120+
121+
initGlobals "1000000"
122+
123+
# Spawning subshells is expensive so run a background task which we can
124+
# probe for liveness to determine when time is up.
125+
local sleepPid
126+
read -rt "$RUNTIME_SEC" <> <(:) & # pure bash sleep
127+
sleepPid=$!
128+
129+
# we are working in microseconds (10^6)
130+
tStart="${EPOCHREALTIME/.}"
131+
132+
while kill -0 "$sleepPid" 2>&3; do
133+
emptyBitArray
134+
runSieve
135+
((++passes))
136+
done
137+
138+
# calculate real runtime
139+
tRun=$((${EPOCHREALTIME/.} - tStart))
140+
141+
printResults "0" "$tRun" "$passes" "$name"
142+
}

PrimeBash/solution_1/PrimeBash.sh

+3-143
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,11 @@
1-
#! /bin/bash
1+
#! /usr/bin/env bash
22
#
33
# A simple prime sieve based on https://github.com/davepl/Primes
44
# Written in bash.
55
#
66
# Tyler Hart (nitepone) <[email protected]>
77

8-
# rbergen -- changed number for 10 from 1 to 4
9-
readonly -A primeCounts=(
10-
[10]=4
11-
[100]=25
12-
[1000]=168
13-
[10000]=1229
14-
[100000]=9592
15-
[1000000]=78498
16-
[10000000]=664579
17-
[100000000]=576145
18-
)
19-
20-
declare sieveSize=0
21-
declare -A bitArray=()
22-
# rbergen: changed runtime to drag-race default
23-
readonly RUNTIME_SEC=5
24-
25-
function sqrt {
26-
# integer square root using binary search (lilweege)
27-
local -n lo=$1 # Output
28-
lo=1
29-
hi=$2
30-
mid=0
31-
while ((lo<=hi)); do
32-
((mid=(lo+hi)/2))
33-
if [[ $((mid*mid)) -le $2 ]]; then
34-
((lo=mid+1))
35-
else
36-
((hi=mid-1))
37-
fi
38-
done
39-
((--lo))
40-
}
41-
42-
function initGlobals {
43-
sieveSize=$1
44-
}
45-
46-
function emptyBitArray {
47-
bitArray=()
48-
}
49-
50-
function validateResults {
51-
local result=$1
52-
(( primeCounts[\$sieveSize] == result ))
53-
}
54-
55-
function countPrimes {
56-
local i count=$((sieveSize >= 2))
57-
for ((i=3; i < sieveSize; i++)); do
58-
if getBit "$i"; then
59-
((++count))
60-
fi
61-
done
62-
echo "$count"
63-
}
64-
65-
function getBit {
66-
# Return failure if even if bitArray is set (determined composite)
67-
# Return success if known prime
68-
(( $1 & 1 && !bitArray[\$1] ))
69-
}
8+
source PrimeBash.common
709

7110
function clearBit {
7211
# Mark as composite
@@ -89,83 +28,4 @@ function runSieve {
8928
done
9029
}
9130

92-
function printResults {
93-
local showresults dur_nano avg_dur_nano dur_str avg_dur_str passes count valid
94-
showresults="$1"
95-
dur_nano="$2"
96-
passes="$3"
97-
# create duration strings from nanosecond duration time
98-
avg_dur_nano=$((dur_nano/passes))
99-
dur_str="$(printf "%d.%09d"\
100-
"$((dur_nano/1000000000))"\
101-
"$((dur_nano%1000000000))"\
102-
)"
103-
avg_dur_str="$(printf "%d.%09d"\
104-
"$((avg_dur_nano/1000000000))"\
105-
"$((avg_dur_nano%1000000000))"\
106-
)"
107-
# create validity string
108-
if validateResults "$(countPrimes)"; then
109-
valid="True"
110-
else
111-
valid="False"
112-
fi
113-
114-
if ((showresults)); then
115-
printf "2, "
116-
fi
117-
118-
count=$((sieveSize >= 2))
119-
for ((num=3; num<sieveSize; num+=2)); do
120-
if getBit "$num"; then
121-
if ((showresults)); then
122-
printf "%s, " "$num"
123-
fi
124-
((count++))
125-
fi
126-
done
127-
128-
if ((count != $(countPrimes))); then
129-
echo "Internal: Print Results Counted Incorrectly..." >&2
130-
exit 1
131-
fi
132-
printf "\n"
133-
printf "Passes: %s, Time: %s, Avg: %s, Limit: %s, Count: %s, Valid: %s\n" \
134-
"$passes" "$dur_str" "$avg_dur_str" "$sieveSize" \
135-
"$count" "$valid"
136-
137-
# rbergen: added drag-race format output
138-
printf "\nbash;%s;%s;1;algorithm=base,faithful=no\n" "$passes" "$dur_str"
139-
}
140-
141-
function main {
142-
export LC_ALL=C
143-
local passes=0 sleepPid tStart tRun
144-
145-
# Keep /dev/null handle open so we don't pay for opening it later
146-
exec 3>/dev/null
147-
148-
initGlobals "1000000"
149-
150-
# Spawning subshells is expensive so run a background task which we can
151-
# probe for liveness to determine when time is up.
152-
local sleepPid
153-
sleep "$RUNTIME_SEC" &
154-
sleepPid=$!
155-
156-
# we are working in nanoseconds (10^9)
157-
tStart=$(date +%s%N)
158-
159-
while kill -0 "$sleepPid" 2>&3; do
160-
emptyBitArray
161-
runSieve
162-
((++passes))
163-
done
164-
165-
# calculate real runtime
166-
tRun=$(($(date +%s%N) - tStart))
167-
168-
printResults "0" "$tRun" "$passes"
169-
}
170-
171-
main
31+
main 'bash'

0 commit comments

Comments
 (0)