This exercise has taught me a lot about POSIX, dash and their limits.
I decided to experiment with fixed point arithmetic using dash
as the shell.
If you want to test it then change the shebang to your directory where 'dash' is or use 'bash' instead.
This was one of the hardest things I have done and it took me around 24 hours to just get addition and subtraction working with an accuracy of nine decimal places for calculation results inside + or - 1,000,000.000000000 and around 5 decimal places for the working limits of 64 bit integer maths of + or - 9223,372,036.85477[????].
I haven't done multiplication and division yet but have checked from the command line that these work and are easy enough now that I have this building block.
It will have bugs and limitations but for small scale quick fixed point calculations this seems to work fine at the moment.
As I once uploaded here, "Is there anything the UNIX shell can't do?" and the script is not that big.
This requires NO external command help to work, it is pure dash shell coding.
I will be finishing the multiplication and division whilst away next week.
#!/usr/local/bin/dash
#
#!/bin/bash
#
# 'calc' - A basic calculator for average sized numbers.
#
# OSX 10.13.6, default bash terminal.
# Another exercise in futility by B.Walker.
# Public Domain.
# Accurate enough to nine decimal places.
# USAGE: calc NUMBER1 +|-|*|/ NUMBER2
#
# In 64 bit mode.
# Total upper limit = +9223372036.85477; 64 bit signed integer = 9223372036854775807.
# Total lower limit = -9223372036.85477; 64 bit signed integer = 9223372036854775808.
# This allows nine places for the decimal component.
# Numerical variables.
NUM1="$1"
NUM2="$3"
# Equalise the decimal places.
FP1=$( printf "%.9f" "$NUM1" )
FP2=$( printf "%.9f" "$NUM2" )
# Calculation mode variable, limited error correction.
CALC="$2"
if [ "$NUM1" = "" ] || [ "$NUM2" = "" ] || [ "$CALC" = "" ]
then
echo "USAGE: calc NUMBER1 +|-|*|/ NUMBER2"
exit 1
fi
# Remove the decimal point(s).
INT1="${FP1%.*}${FP1#*.}"
INT2="${FP2%.*}${FP2#*.}"
# Remove all leading zeros.
INT1=$( printf "%.f" "$INT1" )
INT2=$( printf "%.f" "$INT2" )
# Addition and subtraction.
if [ "$CALC" = "+" ] || [ "$CALC" = "-" ]
then
if [ "$CALC" = "+" ]
then
SUM=$(( (INT1)+(INT2) ))
fi
if [ "$CALC" = "-" ]
then
SUM=$(( (INT1)-(INT2) ))
fi
# Internal Variables.
LENGTH="${#SUM}"
MINUS="$SUM"
FLOAT=""
COUNT="0"
# Detect the minus sign, save and delete.
while [ "$COUNT" -le "$LENGTH" ]
do
MINUS="${MINUS%?}"
if [ "$MINUS" = "-" ]
then
SUM="${SUM#?}"
MINUS="-"
break
fi
COUNT=$(( COUNT+1 ))
done
# Give a positive sign on the final result if it is not negative.
# This condition can be removed if required.
if [ "$MINUS" = "" ]
then
MINUS="+"
fi
# Pad a float result of less that 1.0 with leading zeros if required.
LENGTH=${#SUM}
if [ "$LENGTH" -le "9" ]
then
FLOAT=$( printf "%09d" "$SUM" )
SUM="$FLOAT"
fi
# Obtain the integer part.
INT="${SUM%?????????}"
if [ "$INT" = "" ]
then
INT="0"
fi
# Obtain the float part.
if [ "$LENGTH" -ge "10" ]
then
COUNT="10"
GETFLOAT=""
while [ "$COUNT" -le "$LENGTH" ]
do
GETFLOAT="$GETFLOAT"'?'
COUNT=$(( COUNT+1 ))
done
FLOAT="${SUM#${GETFLOAT}}"
fi
RESULT="${INT}.${FLOAT}"
printf "%s%.9f\n" "$MINUS" "$RESULT"
fi
# Multiplication.
if [ "$CALC" = "*" ]
then
:
fi
# Division.
if [ "$CALC" = "/" ]
then
:
fi
A couple of 'additions' using python 2.7 as a check.
OSX 10.13.6, default bash terminal calling /usr/local/bin/dash
Last login: Mon Nov 5 08:06:19 on ttys000
AMIGA:amiga~> cd Desktop/Code/Shell
AMIGA:amiga~/Desktop/Code/Shell> ./calc 1234567.987654321 - -1234567.135790864
+2469135.123445185
AMIGA:amiga~/Desktop/Code/Shell> python
Python 2.7.10 (default, Oct 6 2017, 22:29:07)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 1234567.987654321 - -1234567.135790864
2469135.123445185
>>> exit()
AMIGA:amiga~/Desktop/Code/Shell> ./calc 0.00001234567890 - 1.012401299
-1.012388953
AMIGA:amiga~/Desktop/Code/Shell> python
Python 2.7.10 (default, Oct 6 2017, 22:29:07)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 0.00001234567890 - 1.012401299
-1.0123889533211
>>> exit()
AMIGA:amiga~/Desktop/Code/Shell> _
Have fun and enjoy...
This is my pet love, getting languages to do something they were not designed to do.
Bazza.