This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
floating_point_calculation [2012/01/27 16:02] k2patel |
floating_point_calculation [2020/08/10 02:35] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Floating Point Calculation ====== | ====== Floating Point Calculation ====== | ||
This is an example represent how to compute Floating point in bash. | This is an example represent how to compute Floating point in bash. | ||
+ | |||
+ | ==== Using in Script for Comparision ==== | ||
+ | |||
+ | To use ''bc'' in our bash scripts we'll package it up into a couple of functions: | ||
+ | |||
+ | <code oobas> | ||
+ | float_eval EXPRESSION | ||
+ | and | ||
+ | float_cond CONDITIONAL-EXPRESSION | ||
+ | </code> | ||
+ | Both functions expect a single floating point expression, ''float_eval'' writes the result of the expression evaluation to standard out, ''float_cond'' assumes the expression is a conditional expression and sets the return/status code to zero if the expression is true and one if it's false. | ||
+ | |||
+ | Usage is quite simple: | ||
+ | |||
+ | <code bash> | ||
+ | float_eval '12.0 / 3.0' | ||
+ | if float_cond '10.0 > 9.0'; then | ||
+ | echo 'As expected, 10.0 is greater than 9.0' | ||
+ | fi | ||
+ | a=12.0 | ||
+ | b=3.0 | ||
+ | c=$(float_eval "$a / $b") | ||
+ | </code> | ||
+ | The code for the functions follows: | ||
+ | |||
+ | <code bash> | ||
+ | #!/bin/bash | ||
+ | # | ||
+ | # Floating point number functions. | ||
+ | |||
+ | ##################################################################### | ||
+ | # Default scale used by float functions. | ||
+ | |||
+ | float_scale=2 | ||
+ | |||
+ | |||
+ | ##################################################################### | ||
+ | # Evaluate a floating point number expression. | ||
+ | |||
+ | function float_eval() | ||
+ | { | ||
+ | local stat=0 | ||
+ | local result=0.0 | ||
+ | if [[ $# -gt 0 ]]; then | ||
+ | result=$(echo "scale=$float_scale; $*" | bc -q 2>/dev/null) | ||
+ | stat=$? | ||
+ | if [[ $stat -eq 0 && -z "$result" ]]; then stat=1; fi | ||
+ | fi | ||
+ | echo $result | ||
+ | return $stat | ||
+ | } | ||
+ | |||
+ | |||
+ | ##################################################################### | ||
+ | # Evaluate a floating point number conditional expression. | ||
+ | |||
+ | function float_cond() | ||
+ | { | ||
+ | local cond=0 | ||
+ | if [[ $# -gt 0 ]]; then | ||
+ | cond=$(echo "$*" | bc -q 2>/dev/null) | ||
+ | if [[ -z "$cond" ]]; then cond=0; fi | ||
+ | if [[ "$cond" != 0 && "$cond" != 1 ]]; then cond=0; fi | ||
+ | fi | ||
+ | local stat=$((cond == 0)) | ||
+ | return $stat | ||
+ | } | ||
+ | |||
+ | |||
+ | # Test code if invoked directly. | ||
+ | if [[ $(basename $0 .sh) == 'float' ]]; then | ||
+ | # Use command line arguments if there are any. | ||
+ | if [[ $# -gt 0 ]]; then | ||
+ | echo $(float_eval $*) | ||
+ | else | ||
+ | # Turn off pathname expansion so * doesn't get expanded | ||
+ | set -f | ||
+ | e="12.5 / 3.2" | ||
+ | echo $e is $(float_eval "$e") | ||
+ | e="100.4 / 4.2 + 3.2 * 6.5" | ||
+ | echo $e is $(float_eval "$e") | ||
+ | if float_cond '10.0 > 9.3'; then | ||
+ | echo "10.0 is greater than 9.3" | ||
+ | fi | ||
+ | if float_cond '10.0 < 9.3'; then | ||
+ | echo "Oops" | ||
+ | else | ||
+ | echo "10.0 is not less than 9.3" | ||
+ | fi | ||
+ | a=12.0 | ||
+ | b=3.0 | ||
+ | c=$(float_eval "$a / $b") | ||
+ | echo "$a / $b" is $c | ||
+ | set +f | ||
+ | fi | ||
+ | fi | ||
+ | |||
+ | # vim: tabstop=4: shiftwidth=4: noexpandtab: | ||
+ | # kate: tab-width 4; indent-width 4; replace-tabs false; | ||
+ | </code> | ||
+ | The work of the functions is done by feeding the arguments to ''bc'': | ||
+ | |||
+ | <code bash> | ||
+ | result=$(echo "scale=$float_scale; $*" | bc -q 2>/dev/null) | ||
+ | </code> | ||
+ | By default ''bc'' outputs its result with no digits to the right of the decimal point and without a decimal point. To change this you have to change one of ''bc'''s builtin variables: ''scale''. This is where the "language" features of ''bc'' are relevant, in ''bc'' as in C statements are separated by semi-colons. We set ''bc'''s ''scale'' variable by preceding the expression that we pass to ''bc'' with ''scale=$float_scale;''. This sets the scale in ''bc'' to the value of the bash global variable ''float_scale'', which is by default set to two (near the top of the script). | ||
+ | |||
+ | The main gotcha here has to do with the fact that "*", "<", and ">" have other meanings in bash. You can eliminate the problem of "<" and ">" by quoting your expressions, but this only works with "*" if you use single quotes and that would mean you couldn't include bash variables in the expression. The other option is to bracket your code with "''set -f''" and "''set +f''" to turn off pathname/wildcard expansion. | ||
+ | |||
+ | If you save the script as ''float.sh'' and run it directly it will execute the test code at the bottom: | ||
+ | |||
+ | <code bash> | ||
+ | $ sh float.sh | ||
+ | 12.5 / 3.2 is 3.90 | ||
+ | 100.4 / 4.2 + 3.2 * 6.5 is 44.70 | ||
+ | 10.0 is greater than 9.3 | ||
+ | 10.0 is not less than 9.3 | ||
+ | 12.0 / 3.0 is 4.00 | ||
+ | </code> | ||
+ | The one unaswered question you may have is: "and why would I want to do this?" Next time around I'll show you one place you can put this to real world use. | ||
+ | |||
+ | Ref : [[ http://www.linuxjournal.com/content/floating-point-math-bash | Linux Journal ]] | ||
+ | |||
+ | ==== Doing Calculation ==== | ||
+ | |||
**Details** | **Details** | ||
Line 129: | Line 254: | ||
</code> | </code> | ||
- | Ref. [[http://www.novell.com/coolsolutions/tools/17043.html|http://www.novell.com/coolsolutions/tools/17043.html]] | + | Ref. [[ http://www.novell.com/coolsolutions/tools/17043.html | Novell Cool Solutions ]] |