add floating point output to math command

This makes it easy for the user to request floating point output with the
desired number of digits after the decimal point (not to be confused with
significant digits).

Note that this is just a thin wrapper so someone can say `math -s3 10 / 3`
rather than `math "scale=3; 10 /3"`.

Resolves #1643
This commit is contained in:
Kurtis Rader 2016-05-02 20:53:48 -07:00
parent 3ad5c7c289
commit d97c22df2d
6 changed files with 74 additions and 21 deletions

View file

@ -1,9 +1,8 @@
\section math math - Perform mathematics calculations \section math math - Perform mathematics calculations
\subsection math-synopsis Synopsis \subsection math-synopsis Synopsis
\fish{synopsis} \fish{synopsis}
math EXPRESSION math [-sN] EXPRESSION
\endfish \endfish
\subsection math-description Description \subsection math-description Description
@ -12,9 +11,26 @@ math EXPRESSION
For a description of the syntax supported by math, see the manual for the bc program. Keep in mind that parameter expansion takes place on any expressions before they are evaluated. This can be very useful in order to perform calculations involving shell variables or the output of command substitutions, but it also means that parenthesis have to be escaped. For a description of the syntax supported by math, see the manual for the bc program. Keep in mind that parameter expansion takes place on any expressions before they are evaluated. This can be very useful in order to perform calculations involving shell variables or the output of command substitutions, but it also means that parenthesis have to be escaped.
The following options are available:
- `-sN` Sets the scale of the result. `N` must be an integer and defaults to zero. This simply sets bc's `scale` variable to the provided value. Note that you cannot put a space between `-s` and `N`.
\subsection return-values Return Values
If invalid options or no expression is provided the return `status` is two. If the expression is invalid the return `status` is three. If bc returns a result of `0` (literally, not `0.0` or similar variants) the return `status` is one otherwise it's zero.
\subsection math-example Examples \subsection math-example Examples
`math 1+1` outputs 2. `math 1+1` outputs 2.
`math $status-128` outputs the numerical exit status of the last command minus 128. `math $status-128` outputs the numerical exit status of the last command minus 128.
`math 10 / 6` outputs `1`.
`math -s0 10.0 / 6.0` outputs `1`.
`math -s3 10 / 6` outputs `1.666`.
\subsection math-cautions Cautions
Note that the modulo operator (`x % y`) is not well defined for floating point arithmetic. The `bc` command produces a nonsensical result rather than emit an error and fail in that case. It doesn't matter if the arguments are integers; e.g., `10 % 4`. You'll still get an incorrect result. Do not use the `-sN` flag with N greater than zero if you want sensible answers when using the modulo operator.

View file

@ -1,23 +1,42 @@
function math --description "Perform math calculations in bc" function math --description "Perform math calculations in bc"
if count $argv >/dev/null set -l scale 0 # default is integer arithmetic
switch $argv[1]
case -h --h --he --hel --help
__fish_print_help math
return 0
end
# Stitch lines together manually if set -q argv[1]
# we can't rely on BC_LINE_LENGTH because some systems don't have a bc version "new" enough switch $argv[1]
set -l out (echo $argv | bc | string replace -r '\\\\$' '' | string join '') case '-s*' # user wants to specify the scale of the output
test -z "$out"; and return 1 set scale (string replace -- '-s' '' $argv[1])
echo $out if not string match -q -r '^\d+$' "$scale"
switch $out echo 'Expected an integer to follow -s' >&2
case 0 return 2 # missing argument is an error
return 1 end
end set -e argv[1]
return 0
end
return 2
case -h --h --he --hel --help
__fish_print_help math
return 0
end
end
if not set -q argv[1]
return 2 # no arguments is an error
end
# Stitch lines together manually. We can't rely on BC_LINE_LENGTH because some systems don't
# have a new enough version of bc.
set -l out (echo "scale=$scale; $argv" | bc | string replace -r '\\\\$' '' | string join '')
switch "$out"
case ''
# No output indicates an error occurred.
return 3
case 0
# For historical reasons a zero result translates to a failure status.
echo 0
return 1
case '*'
# For historical reasons a non-zero result translates to a success status.
echo $out
return 0
end
end end

0
tests/math.err Normal file
View file

9
tests/math.in Normal file
View file

@ -0,0 +1,9 @@
math 3 / 2
math 10/6
math -s0 10 / 6
math -s3 10/6
math '10 % 6'
math -s0 '10 % 6'
math '23 % 7'
math -s6 '5 / 3 * 0.3'
true

8
tests/math.out Normal file
View file

@ -0,0 +1,8 @@
1
1
1
1.666
4
4
2
.499999

1
tests/math.status Normal file
View file

@ -0,0 +1 @@
0