How to round to 1 decimal in bash? - bash

I am trying my first script on bash and I am not able to round (not truncate).
So, I am getting 55.08 and I would like to convert it to 55.1
promedio=$(echo "scale=2; $lineas/($dias*24)" | bc)
Note that I am currently using scale=2 because scale=1 produces 55.0.
Thank you all :)

This is not so much a bash question as a bc one, but bc doesn’t round. The easiest approach is probably just to add .05 after the division, then set scale to 1 and divide by 1 to force truncation.
You can do that by using a variable inside bc to hold the unrounded result:
promedio=$(bc <<<"scale=2; p=$lineas/($dias*24); scale=1; (p+0.05)/1")
Or you could do it all in one go by throwing in an extra multiplication by 10, rounding at that magnitude, and then dividing back down:
promedio=$(bc <<<"scale=1; (10*$lineas/($dias*24)+0.5)/10")

Related

Unexpected arithmetic result with zero padded numbers

I have a problem in my script wherein I'm reading a file and each line has data which is a representation of an amount. The said field always has a length of 12 and it's always a whole number. So let's say I have an amount of 25,000, the data will look like this 000000025000.
Apparently, I have to get the total amount of these lines but the zero prefixes are disrupting the computation. If I add the above mentioned number to a zero value like this:
echo $(( 0 + 000000025000 ))
Instead of getting 25000, I get 10752 instead. I was thinking of looping through 000000025000 and when I finally get a non-zero value, I'm going to substring the number from that index onwards. However, I'm hoping that there must be a more elegant solution for this.
The number 000000025000 is an octal number as it starts with 0.
If you use bash as your shell, you can use the prefix 10# to force the base number to decimal:
echo $(( 10#000000025000 ))
From the bash man pages:
Constants with a leading 0 are interpreted as octal numbers. A leading 0x or 0X denotes hexadecimal. Otherwise, numbers take the form [base#]n, where the optional base is a decimal number between 2 and 64 representing the arithmetic base, and n is a number in that base.
Using Perl
$ echo "000000025000" | perl -ne ' { printf("%d\n",scalar($_)) } '
25000

How to count 100=(100/24)*24 in bash?

I try to perform this simple calculation, but the programm always gives me incorrect results. If I use only integers, then I get 96
var=$(((100/24)*24))
even if I try to use bc:
var=$(bc <<< "scale=100;100/24*24")
I get something like this:
99.99999999999999999999999999999999999999999999999999999999999999999
99999999999999999999999999999999984;
How to let make the program count the correct way? So that I could get the same values as from the calculator?
This is the result of rounding, to integers (100/24 -> 4 in bash) and floating point (bc lacks a "round" function). See this SO question for related information and links.
It's very hard to provide a general solution here: Most solutions depend on your exact use case, which is probably not what you posted in your question (otherwise you could just put var=100 and move on).
One technique is to reorder the problem (var=$((24*100/24))), which would keep all operations integers.
Another is to multiply by a large offset (var_millionths=$((1000000*(100/24)*24))) and divide out as needed, which would keep enough precision that Bash could round the result well.
Finally, you could (ab)use printf to perform the rounding step for you, because you want the number to be round in base 10 (i.e. when printed):
printf "%.0f\n" $(BC_LINE_LENGTH=0 bc <<< "scale=100;100/24*24")

Convert floating point numbers to integer without rounding in bash

I have a input file with set of float numbers like 2.45, 3.56, 54,64and so on. I need to sum them.
After reading the this article I understand that there is no straight way to do that. I can't round any numbers.
I remember that there are a way to convert in to int without rounding. Like 2.54 * 100 = 254. After that I can do all math and return it to float view using AWK.
I was trying to use bc tool, but it wont work this way.
Like, (wrong code)
a=2.54
c=$((a * 100)) | bc -l
Please, suggest
Not duplicate, because:
I'm asking and looking to convert floating point numbers to integers, not to compare 2 floating numbers. I need to SUM it, and it is different from comparison. Besides, that question doesn't answer on my question.
Point of asking here is to get closest possible answer for particular question.
You could use awk,
$ echo '2.45, 3.56, 54,64' | awk -v FS=" *, *" '{for(i=1;i<=NF;i++){count = count+$i}}END{print count}'
124.01

Arithmetic with variable [duplicate]

This question already has answers here:
How do I use floating-point arithmetic in bash?
(23 answers)
Closed 8 years ago.
I need to perform some arithemic with bash.It goes like this
VariableA = (VariableB-VariableC) / 60
Variable A should be approximated to 2 decimal places
I don't know which one of these is the right answer(Don't have a linux server at hand atm to test)
VariableA = $((VariableB-VariableC)/60)
VariableA = $(((VariableB-VariableC)/))/60)
It would be nice if someone could also help me out about how to round the VariableA to 2 decimal places without using third party tools like bc
The bash itself can compute only integer values, so if you need to use a fixed number of decimals, you can shift your decimal point (it's like computing in cents instead of dollars or euros). Then only at the output you need to make sure there's a . before the last two digits of your number:
a=800
b=300
result=$((a*100/b)) # factor 100 because of division!
echo "${result:0:-2}.${result: -2}"
will print 2.66.
If you want to make computations in floating points, you should use a tool like bc to do that for you:
bc <<<'scale=2; 8.00/3.00'
will print out 2.66.

Regex for floating point?

I'm trying to write a RegEx to validate a floating point number. Here's what I've managed thus far:
/^[-+]?[1-9]\d{0,2}(\.\d{1,1})?/
The number is valid if:
Either positive or negative
Max of 2 digits (tens or hundreds)
Hundredths digit can't 0 (only 1-9)
Scale is max of 1
Decimal value can be 0 or 5 or none at all
So these numbers would be valid, for ex:
1.5
-1.5
17.5
15
-3
30.5
These numbers would be invalid, for ex:
1.57
3041.5
17.59
915
-1.56
05.0
How about Float(number) (catch exceptions to detect parse errors) and then verify the floating point number? This will be easier for several of the properties than writing a regex. If you need to force a subset of the syntax accepted by Ruby to be used (why?), check only that part with a regex.
As I said in the comments - your first non-zero digit will count, then you add two more - which will now allow three-digit numbers like 915. To solve this the regexp way (with your testcases):
^[+-]?(?:(?!0)\d{1,2}|0)(?:\.[05])?$
I use negative lookahead (?!0) to make sure the first digit is not a zero, then just require the desired number of digits. It also allows 0.5 and similar through the |0 disjunction. If you prefer .5, it'll be this:
^[+-]?(?!0)\d{,2}(?:\.[05])?$
If you want to disallow 3.0 (allowed by your rules) and only allow 3 (as you imply in the examples), replace the last part:
^[+-]?(?:(?!0)\d{1,2}|0)(?:\.5)?$
However, this is much less readable than #Arkku's nice Float(number); use regexps if you really need them.
Here's a whole webpage on validating floats in regular expressions: http://www.regular-expressions.info/floatingpoint.html
That said,
{1,1} is equivalent to {1} which is equivalent to not putting it at all, so you can remove it
If you want to make sure that 0.5xyz doesn't pass, then add a $ at the end
With the above changes, it'd look like this: /^[-+]?[1-9]\d{0,2}(\.\d)?$/
According to your valid and invalid examples on: Regex for floating point?
This regex would work:
^[+-]?([1-9][0-9]?|0)(\.[05])?$
/^[-+]?\d{0,2}(\.[05])?(?!\d)$/
Matches when:
Value is either positive or negative
magnitude is less than 100. in the range of (-99.5 to 99.5)
Decimal value is .0 or .5 or absent (in other words, .0 or .5, or missing)
So these numbers would be valid, for ex:
1.5
-1.5
17.5
15
-3
30.5
-10.0
99.5
These numbers would be invalid, for ex:
1.57
3041.5
17.59
915
-1.56
05.0
99.6

Resources