Arithmetic operation and for loop in terminal [duplicate] - bash

Here is my script:
d1=0.003
d2=0.0008
d1d2=$((d1 + d2))
mean1=7
mean2=5
meandiff=$((mean1 - mean2))
echo $meandiff
echo $d1d2
But instead of getting my intended output of:
0.0038
2
I am getting the error Invalid Arithmetic Operator, (error token is ".003")?

bash does not support floating-point arithmetic. You need to use an external utility like bc.
# Like everything else in shell, these are strings, not
# floating-point values
d1=0.003
d2=0.0008
# bc parses its input to perform math
d1d2=$(echo "$d1 + $d2" | bc)
# These, too, are strings (not integers)
mean1=7
mean2=5
# $((...)) is a built-in construct that can parse
# its contents as integers; valid identifiers
# are recursively resolved as variables.
meandiff=$((mean1 - mean2))

Another way to calculate floating numbers, is by using AWK rounding capability, for example:
a=502.709672592
b=501.627497268
echo "$a $b" | awk '{print $1 - $2}'
1.08218

In case you do not need floating point precision, you may simply strip off the decimal part.
echo $var | cut -d "." -f 1 | cut -d "," -f 1
cuts the integer part of the value. The reason to use cut twice is to parse integer part in case a regional setting may use dots to separate decimals and some others may use commas.
Edit:
Or, to automate the regional settings one may use locale.
echo $var | cut -d $(locale decimal_point) -f 1

You can change the shell which you are using. If you are executing your script with bash shell bash scriptname.sh try using ksh for your script execution. Bash doesn't support arithmetic operations that involve floating point numbers.

Big shout-out to the bc command - it totally saved my day! It's a simple answer, but it worked like a charm.
a=1.1
b=1.1
echo $a + $b | bc -l
# Output:
2.2
#SUM
sum=$(echo $a + $b | bc -l)
echo $sum
# Output
2.2
bc is a command-line calculator, which allows users to perform mathematical calculations on the terminal.

Related

How to do binary addition in bash

I am trying to add two 32 bit binary numbers. One of them is a constant (address_range_in_binary) , and another one is an element of an array (IPinEachSubnet[$val])
I am trying to follow the instructions here, but I could not figure out how to get it done using variables. I have been trying to use different combinations of the below, but none of them seems to work. It is probably a simple syntax issue. Any help would be appreciated. The following is printing some negative random values.
For example, if the values are as following:
$address_range_in_binary=00001010001101110000101001000000
$IPinEachSubnet[$val]=00000000000000000000000000010000
echo "ibase=2;obase=2;$((address_range_in_binary+IPinEachSubnet[$val]))" | bc -l
The output of this is -1011101110111111110
bash only solution
y=2#00001010001101110000101001000000
t=2#00000000000000000000000000010000
oct=$(printf '%o' $(( y + t ))) # no bin format in printf
o2b=({0..1}{0..1}{0..1})
r=''
for (( i=0; i<${#oct}; i++ ))
do
r+=${o2b[${oct:$i:1}]}
done
echo $r
the conversion from oct to bin is inspired in Bash shell Decimal to Binary conversion
Let's define your variables (I will use shorter names):
$ y=00001010001101110000101001000000
$ t=00000000000000000000000000010000
Now, let's run the command in question:
$ echo "ibase=2;obase=2;$((y+t))" | bc -l
-1011101110111111111
The above produces that incorrect result that you observed.
To get the correct result:
$ echo "ibase=2;obase=2; $y+$t" | bc -l
1010001101110000101001010000
Discussion
The command $((y+t)) tells bash to do the addition assuming that the numbers are base-10. The result of bash's addition is passed to bc. This is not what you want: You want bc to do the addition.
Using an array
$ y=00001010001101110000101001000000
$ arr=(00000000000000000000000000010000)
$ echo "ibase=2;obase=2; $y+${arr[0]}" | bc -l
1010001101110000101001010000

bash command line arithmetic echo $((x-y)) how to divide result by z?

I'm trying to figure out a way to take the result of a basic equation and divide by another integer. So in in simple form it looks like;
A-B = C and then divide C by D
I understand the first part of the equation is echo $((A-B)) but how do I get that result divided by D?
Any feedback would be greatly appreciated!
Using shell
This (taken from the comments) fails because the parentheses are unbalanced:
$ echo $((2147483633-807279114))/5184000))
Try instead:
$ echo $(( (2147483633-807279114)/5184000 ))
258
The above returns an integer because the shell only does integer arithmetic.
Using bc
If you want accurate floating-point numbers, the standard tool to use is bc:
$ echo '(2147483633-807279114)/5184000' | bc -l
258.52710628858024691358
Using python
Python supports both integer and floating point arithmetic:
$ python -c 'print (2147483633-807279114)//5184000'
258
$ python -c 'print (2147483633-807279114)/5184000.0'
258.527106289
Python, with its numpy extension, is an excellent tool even if your needs extend to complex scientific calculations.
Using awk
awk, a standard unix tool, supports floating-point math:
$ awk 'BEGIN{print (2147483633-807279114)/5184000;quit}'
258.527
You can do calculations inside $(( ))
If you want to calculate (A-B)/C, you can put that inside $(( )):
echo $(( (A-B)/C ))
Note that the result will be truncated towards zero, because bash does not support decimals.
Remember to make sure that you have $(( before the expression and )) after, and that all the parentheses inside match up.
dc <<< "$A $B - $D / p"
Note 1: p prints the final result
Note 2: With dc you need to first enter the numbers and then operation

Negative number in bash shell scripting

I need some help with a bash mathematical expression script. I need the expression below to be a negative 2 to the power of 63 but I have tried all sorts of combinations from "", '', (()) and even keeping the positive value but multiplying it by -1 but I can't seem to get the syntax right.
Original expression:
kw=`expr 2^63 | bc`
gives me 9223372036854775808 (which is correct) but I need to get a -9223372036854775808.
I want to be able to do a kw=expr -2^63 | bc to get a negative results but it's not as straight-forward as I'd hoped. Hence my numerous attempts of different permutations to the expression.
Any help will be very appreciated.
Here you go:
$ kw=$(echo -2^63 | bc)
$ echo $kw
-9223372036854775808
UPDATE
#DigitalTrauma is right, if you're in bash, then using a bash here string is better (one less process, more efficient):
kw=$(bc <<< -2^63)
Since this is bash, you don't even need the echo; you can use a bash here string instead:
$ kw=$(bc <<< -2^63)
$ echo $kw
-9223372036854775808

What is the range of typeset -i variable

Below is my script
#!/bin/sh
typeset resl=$(($1+$2))
echo $resl
when i am passing two value 173591451 and 2000252844 to shell script, it is returning negative value.
./addvalue.sh 173591451 2000252844
output ---> -2121123001
Please let me know how we can fix this problem?
Dropping into a friendly programming calculator application to look at your values in hex I see you are into 32-bits of precision. Once you hit 32-bits (8'th digit >= 8) you have exceeded the size of integer your shell was compiled with and entered the land of negative numbers (but that's another post).
0x81923B47 = 0xA58CB9B + 0x77396FAC
Two workarounds, without having to worry about getting a 64-bit shell, follow.
1. awk
The success of this depends on how your awk as compiled and which awk you are using.
awk 'END {print 173591451 + 2000252844}' </dev/null
Also do all your relational testing in awk.
2. dc
The "dc" program (desk calculator) uses arbitrary precision so you never need to worry about integer bit-size again. To put it into a variable:
$ sum="$( echo 173591451 2000252844 + p | dc )"; echo $sum
2173844295
And avoid typeset -i with dc as the shell needs to see strings. Properly checking relationships (if $a < $b) gets a little tricky, but can be done ($a -lt $b is wrong).

how to remove decimal from a variable?

how to remove decimal place in shell script.i am multiplying MB with bytes to get value in bytes .I need to remove decimal place.
ex:-
196.3*1024*1024
205835468.8
expected output
205835468
(You did not mention what shell you're using; this answer assumes Bash).
You can remove the decimal values using ${VAR%.*}. For example:
[me#home]$ X=$(echo "196.3 * 1024 * 1024" | bc)
[me#home]$ echo $X
205835468.8
[me#home]$ echo ${X%.*}
205835468
Note that this truncates the value rather than rounds it. If you wish to round it, use printf as shown in Roman's answer.
The ${variable%pattern} syntax deletes the shortest match of pattern starting from tbe back of variable. For more information, read http://tldp.org/LDP/abs/html/string-manipulation.html
Use printf:
printf %.0f $float
This will perform rounding. So if float is 1.8, it'll give you 2.

Resources