blob: cf77d76874ca65ef30d1dac967a0da64b49ecf38 [file] [log] [blame]
#! /bin/bash
gen()
{
limit="$1"
shift
result=$(dd if=/dev/urandom bs="$limit" count=1 2>/dev/null | od -t u4 | awk 'NR==1 {print $2}')
echo -n "$result"
}
neg()
{
result=$(gen 1)
result="$((result & 1))"
echo -n "$result"
}
zero()
{
result=$(gen 1)
echo -n "$result"
}
limit()
{
max="$1"
shift
result=$(gen 1)
result=$(expr "$result" % "$max")
echo -n $(expr "$result" + 1)
}
num()
{
n=""
neg=$1
shift
real=$1
shift
zero=$1
shift
if [ "$#" -gt 0 ]; then
limit="$1"
shift
else
limit="$(limit 4)"
fi
if [ "$zero" -ne 0 ]; then
z=$(zero)
else
z=1
fi
if [ "$z" -eq 0 ]; then
n="0"
else
if [ "$neg" -ne 0 ]; then
neg=$(neg)
if [ "$neg" -eq 0 ]; then
n="-"
fi
fi
g=$(gen $limit)
n="${n}${g}"
if [ "$real" -ne 0 ]; then
z=$(neg)
if [ "$z" -ne 0 ]; then
limit=$(limit 25)
g=$(gen $limit)
n="$n.$g"
fi
fi
fi
echo -n "$n"
}
ops=( '+' '-' '*' '/' '%' '^' )
files=( "add" "subtract" "multiply" "divide" "modulus" "power" "sqrt" "exponent"
"log" "arctangent" "sine" "cosine" "bessel" )
funcs=( "sqrt" "e" "l" "a" "s" "c" "j" )
script="$0"
testdir=$(dirname "$script")
if [ "$#" -gt 0 ]; then
bc="$1"
shift
else
bc="$testdir/../bc"
fi
out1="$testdir/../.log_bc.txt"
out2="$testdir/../.log_test.txt"
finish() {
rm -rf "$out1" "$out2"
}
trap finish EXIT
t=0
while true; do
line=""
operator=$(gen 1)
op=$(expr "$operator" % 13)
if [ "$op" -lt 6 ]; then
line="$(num 1 1 1) ${ops[$op]}"
if [ "$op" -eq 3 -o "$op" -eq 4 ]; then
number=$(num 1 1 0)
scale=$(num 0 0 1 1)
scale=$(echo "s = $scale % 25; s /= 1; s" | bc)
line="scale = $scale; $line"
elif [ "$op" -eq 5 ]; then
number=$(num 1 0 1 1)
else
number=$(num 1 1 1)
fi
line="$line $number"
else
if [ "$op" -eq 6 ]; then
number=$(num 0 1 1)
# GNU bc gets "sqrt(1) wrong, so skip it.
if [ "$number" == "1" ]; then
t=$(expr "$t" + "1")
continue
fi
elif [ "$op" -eq 7 -o "$op" -eq 12 ]; then
number=$(num 1 1 1 1)
if [ "$op" -eq 12 ]; then
number=$(echo "n = $number % 100; scale = 8; n /= 1; n" | bc)
fi
else
number=$(num 1 1 1)
fi
func=$(expr "$op" - 6)
line="${funcs[$func]}($number"
if [ "$op" -ne 12 ]; then
line="$line)"
else
n=$(num 1 1 1)
n=$(echo "n = $n % 100; scale = 8; n /= 1; n" | bc)
line="$line, $n)"
fi
fi
echo "Test $t: $line"
echo "$line; halt" | bc -lq > "$out1"
content=$(cat "$out1")
if [ "$content" == "" ]; then
echo " other bc returned an error ($error); continuing..."
t=$(expr "$t" + "1")
continue
elif [ "$content" == "-0" ]; then
echo "0" > "$out1"
fi
echo "$line; halt" | "$bc" "$@" -lq > "$out2"
error="$?"
if [ "$error" -ne 0 ]; then
echo " bc returned an error ($error); exiting..."
exit "$error"
fi
diff "$out1" "$out2" > /dev/null
error="$?"
if [ "$error" -ne 0 ]; then
# This works around a bug in GNU bc that gets some
# transcendental functions slightly wrong.
if [ "$op" -ge 7 ]; then
# Have GNU bc calculate to one more decimal place and truncate by 1.
content=$(echo "scale += 10; $line; halt" | bc -lq)
content=${content%??????????}
echo "$content" > "$out1"
# Compare the truncated.
diff "$out1" "$out2" > /dev/null
error="$?"
# GNU bc got it wrong.
if [ "$error" -eq 0 ]; then
echo " failed because of bug in other bc; continuing..."
t=$(expr "$t" + "1")
continue
fi
content=$(echo "scale += 1; $line; halt" | "$bc" "$@" -lq > "$out2")
content=${content%?}
echo "$content" > "$out2"
# Compare the truncated.
diff "$out1" "$out2" > /dev/null
error="$?"
# This bc is off by more than one digit.
if [ "$error" -eq 0 ]; then
echo " failed; off by only one digit,\n"
echo " which is good enough; continuing..."
t=$(expr "$t" + "1")
continue
fi
fi
echo " failed; adding \"$line\" to test suite..."
echo "$line" >> "$testdir/${files[$op]}.txt"
cat "$out1" >> "$testdir/${files[$op]}_results.txt"
echo " exiting..."
exit 127
fi
t=$(expr "$t" + "1")
done