No need for bash
, plain sh
will do as well:
#! /bin/sh -
IFS=+; echo "$(($*))"
$*
in POSIX shells, expands to the list of positional parameters (in this case, the arguments to the script) separated by the first character of $IFS
(or space if $IFS
is unset or nothing if $IFS
is empty). $((...))
is the shell internal arithmetic expansion operator (note that it supports decimal, octal and hexadecimal numbers)
If you need floating point support, that's where you'll need a different shell like ksh93
or zsh
(not bash
as bash
only supports integer arithmetic), though you could also use awk
:
#! /usr/bin/awk -f
BEGIN {t=0; for (i in ARGV) t+=ARGV[i]; print t}
That will use long
(for integer) and double
(for floating point) type numbers as implemented by your system. The input numbers must be decimal floating point or engineering notation in the English style (floating point delimiter is the period character regardless of the locale). With some awk
implementations, it will fail if the first number is negative as awk
would try to interpret it as an option.
Some awk
implementations like GNU awk
when POSIXLY_CORRECT is in the environment also support hexadecimals including with binary exponent notations. Or with --non-decimal-data
, it understands octals and hexadecimals:
$ POSIXLY_CORRECT=1 ./sum 0xap3 0xa
90 # (0xa * 2^3) + 0xa
$ awk --non-decimal-data -f ./sum 010
8
Rounding floating point numbers
What does "rounding a floating point number" mean?
That's easy, obviously... Where's my math book from school...
No, we already know nothing related to floating point numbers is easy:
For a start, there are multiple rounding modes:
Rounding upwards?
Rounding downwards?
Rounding to zero?
Rounding to nearest - ties to even?
Rounding to nearest - ties away from zero?
How to handle the corner cases? How to find out which are the corner cases?
OK, looks like we better use an implementation of the IEEE 754 standard, and let our system take care of that.
To round a floating point number in the shell, based on standard floating point arithmetic, we need three steps:
- Convert the input text from a command line argument to a standard floating point number.
- Round the floating point number using the normal IEEE 754 implementation.
- Format the number as a string for output.
Turns out that the shell command printf
can do all of this. It can be used to print numbers according to a format specification as described in man 3 printf
. The numbers are rounded implicitly in the standard way if it is required for the output format:
The command
Round x
to p
digits precision with input as command line arguments:
printf "%.*f\n" "$p" "$x"
Or in a shell pipeline, with input of x
on standard input, and p
as argument:
echo "$x" | xargs printf "%.*f\n" "$p"
Examples:
$ printf '%.*f\n' 0 6.66
7
$ printf '%.*f\n' 1 6.66
6.7
$ printf '%.*f\n' 2 6.66
6.66
$ printf '%.*f\n' 3 6.66
6.660
$ printf '%.*f\n' 3 6.666
6.666
$ printf '%.*f\n' 3 6.6666
6.667
Bad traps
Beware the locale! It specifies the separator between the integral and fraction part - the .
, as you may expect.
But see yourself what happens in a German locale, for example:
$ LC_ALL=de_DE.UTF-8 printf '%.*f\n' 3 6.6666
6,667
Yes, that's right 6,667
- six comma six six seven. That would mess up your script for sure.
(But only for the two customers in Germany. Except for the developer's machines currently debugging for these customers.)
More robust
To make it more robust, use:
LC_ALL=C /usr/bin/printf "%.*f\n" "$p" "$x"
or
echo "$x" | LC_ALL=C xargs /usr/bin/printf "%.*f\n" "$p"
This also uses /usr/bin/printf
instead of the shell builtin of bash
or zsh
to work around minor inconsistencies in implementation of the printf
variants, and prevent a very dirty effect when, in a German locale, LC_ALL
is set, but not exported. Then, the builtin uses ,
, and /usr/bin/printf
uses .
...
See also %g
for rounding to a specified number of significant digits.
Best Answer
There are lots of options!!!
Summary
Details
Shells
You can use POSIX arithmetic expansion for integer arithmetic
echo "$((...))"
:Quite portable (
ash dash yash bash ksh93 lksh zsh
):Using printf ability to print floats we can extend most shells to do floating point math albeit with a limited range (no more than 10 digits):
ksh93
,yash
andzsh
do support floats here:only
ksh93
(directly) andzsh
loading library mathfunc here:(
zsh
need to loadzmodload zsh/mathfunc
to get functions likeatan
).Interactively with zsh:
With (t)csh (integer only):
In the
rc
shell family,akanga
is the one with arithmetic expansion:POSIX toolchest
bc
(see below for interactive mode), manual hereMnemonic: best calculator (though the
b
is in fact for basic).(supports arbitrary precision numbers)
bc interactive mode:
Rush's solution,
expr
(no interactive mode):Joshua's solution:
awk
(no interactive mode):Other more or less portable tools
Arcege's solution,
dc
(interactive mode:dc
):Which is even more fun since it works by reverse polish notation.
But not as practical unless you work with reverse polish notation a lot.
Note that
dc
predatesbc
andbc
has been historically implemented as a wrapper arounddc
butdc
was not standardised by POSIXDQdims's
calc
(requiredsudo apt-get install apcalc)
:General purpose language interpreters:
manatwork's solution,
node
(interactive mode:node
; output function not needed):Perl (interactive mode:
perl -de 1
):Python (interactive mode:
python
; output function not needed):Also supports arbitrary precision numbers:
If you have
clisp
installed, you can also use polish notation:Marco's solution,
lua
(interactive mode:lua
):PHP (interactive mode:
php -a
):Ruby (interactive mode:
irb
; output function not needed):Guile (interactive mode:
guile
):S-Lang (interactive mode:
slsh
; output function not needed, just a;
terminator):Tcl (interactive mode:
tclsh
; output function not needed, butexpr
is):Javascript shells:
Various SQL's:
SQLite (interactive mode:
sqlite3
):MySQL:
PostgreSQL:
_The options on mysql and postgres stop the 'ascii art' image !
Specialised math-oriented languages:
R in plain mode - lets generate 1000 Normal random numbers and get the standard deviation and print it
R using the littler script - lets print pi squared
PARI/GP, an extensive computer algebra system for number theory, linear algebra, and many other things
GNU Octave (a high-level interpreted language, primarily intended for numerical computations)
Also supports complex numbers:
Julia, high-performance language and interpreter for scientific and numerical computing.
Non-interactive option:
GhostScript GhostScript is a PostScript interpreter, very commonly installed even in very old distributions.
See PostScript docs for a list of supported math commands.
Interactive example: