Как округлить десятичные дроби с помощью bc в bash?

Краткий пример того, что я хочу, используя сценарии bash:

#!/bin/bashecho "Insert the price you want to calculate:"read floatecho "This is the price without taxes:"echo "scale=2; $float/1.18" |bc -lread -p "Press any key to continue..."bash scriptname.sh

Предполагая, что цена составляет: 48,86, ответ будет: 41,406779661 (на самом деле 41,40, потому что я использую scale=2;)

Мой вопрос заключается в следующем:Как я округляю вторую десятичную дробь, чтобы показать ответ таким образом?: 41.41

Самое простое решение:

printf %.2f $(echo "$float/1.18" | bc -l)

Функция bash round:

round(){echo $(printf %.$2f $(echo "scale=$2;(((10^$2)*$1)+0.5)/(10^$2)" | bc))};

Используется в вашем примере кода:

#!/bin/bash# the function "round()" was taken from # http://stempell.com/2009/08/rechnen-in-bash/# the round function:round(){echo $(printf %.$2f $(echo "scale=$2;(((10^$2)*$1)+0.5)/(10^$2)" | bc))};echo "Insert the price you want to calculate:"read floatecho "This is the price without taxes:"#echo "scale=2; $float/1.18" |bc -lecho $(round $float/1.18 2);read -p "Press any key to continue..."

Удачи :o)

Округление Bash/awk:

echo "23.49" | awk '{printf("%d\n",$1 + 0.5)}'  

Если у вас есть python, вы можете использовать что-то вроде этого:

echo "4.678923" | python -c "print round(float(raw_input()))"

Вот чисто коммерческое решение. Правила округления: при +/- 0,5 округлять от нуля.

Поместите шкалу, которую вы ищете, в $result_scale; ваша математика должна быть там, где находится $MATH в списке команд bc:

bc <<MATHh=0scale=0/* the magnitude of the result scale */t=(10 ^ $result_scale)/* work with an extra digit */scale=$result_scale + 1/* your math into var: m */m=($MATH)/* rounding and output */if (m < 0) h=-0.5if (m > 0) h=0.5a=(m * t + h)scale=$result_scalea / tMATH

Вот сокращенная версия вашего скрипта, исправленная, чтобы обеспечить желаемый результат:

#!/bin/bashfloat=48.86echo "You asked for $float; This is the price without taxes:"echo "scale=3; price=$float/1.18 +.005; scale=2; price/1 " | bc

Обратите внимание, что округление до ближайшего целого числа эквивалентно добавлению .5 и взятию слова или округлению в меньшую сторону (для положительных чисел).

Кроме того, масштабный коэффициент применяется во время операции; так что (это bc команды, вы можете вставить их в свой терминал):

float=48.86; rate=1.18; scale=2; p2=float/ratescale=3; p3=float/ratescale=4; p4=float/rateprint "Compare:  ",p2, " v ", p3, " v ", p4Compare:  41.40 v 41.406 v 41.4067# however, scale does not affect an entered value (nor addition)scale=0a=.0059/1009/10+a.005# let's try roundingscale=2p2+a41.405p3+a41.411(p2+a)/141.40(p3+a)/141.41

Чистая реализация bc в соответствии с запросом

define ceil(x) { auto os,xx;x=-x;os=scale;scale=0 xx=x/1;if(xx>x).=xx-- scale=os;return(-xx)}

если вы поместите это в файл с именем functions.bc, то вы можете округлить его с помощью

echo 'ceil(3.1415)' | bc functions.bc

Код для реализации bc, найденный на http://phodd.net/gnu-bc/code/funcs.bc

если у вас есть результат, например, рассмотрите 2.3747888

все, что вам нужно сделать, это:

d=$(echo "(2.3747888+0.5)/1" | bc); echo $d

это округляет число правильно. Пример:

(2.49999 + 0.5)/1 = 2.99999 

десятичные дроби удаляются с помощью bc и поэтому он округляется до 2, как и должно было быть

#!/bin/bash# - loosely based on the function "round()", taken from # http://stempell.com/2009/08/rechnen-in-bash/# - inspired by user85321 @ askubuntu.com (original author)#   and Aquarius Power# the round function (alternate approach):round2(){    v=$1    vorig=$v    # if negative, negate value ...    (( $(bc <<<"$v < 0") == 1 )) && v=$(bc <<<"$v * -1")    r=$(bc <<<"scale=$3;(((10^$3)*$v/$2)+0.5)/(10^$3)")    # ... however, since value was only negated to get correct rounding, we     # have to add the minus sign again for the resulting value ...    (( $(bc <<< "$vorig < 0") == 1 )) && r=$(bc <<< "$r * -1")    env printf %.$3f $r};echo "Insert the price you want to calculate:"read floatecho "This is the price without taxes:"round2 $float 1.18 2echo && read -p "Press any key to continue..."

На самом деле это просто: нет необходимости явно добавлять жестко закодированный вариант "-0.5" для отрицательных чисел. Выражаясь математически, мы просто вычислим абсолютное значение о споре и все еще добавлять 0,5, как обычно. Но поскольку у нас (к сожалению) нет встроенного abs() функция в нашем распоряжении (если мы не закодируем ее), мы просто отрицать аргумент, если он отрицательный.

Кроме того, оказалось очень громоздко работать с коэффициент в качестве параметра (поскольку для моего решения я должен иметь возможность получать доступ к делителю и делителю отдельно). Вот почему в моем скрипте есть дополнительный третий параметр.

Я все еще ищу чистого bc ответ на вопрос о том, как округлить только одно значение внутри функции, но вот чистый bash ответ:

#!/bin/bashecho "Insert the price you want to calculate:"read floatecho "This is the price without taxes:"embiggen() {  local int precision fraction=""  if [ "$1" != "${1#*.}" ]; then  # there is a decimal point    fraction="${1#*.}"       # just the digits after the dot  fi  int="${1%.*}"              # the float as a truncated integer  precision="${#fraction}"   # the number of fractional digits  echo $(( 10**10 * $int$fraction / 10**$precision ))}# round down if negativeif [ "$float" != "${float#-}" ]  then round="-5000000000"  else round="5000000000"fi# calculate rounded answer (sans decimal point)answer=$(( ( `embiggen $float` * 100 + $round ) / `embiggen 1.18` ))int=${answer%??}  # the answer as a truncated integerecho $int.${answer#$int}  # reassemble with correct precisionread -p "Press any key to continue..."

По сути, это тщательно извлекает десятичные дроби, умножает все на 100 миллиардов (101⁰, 10**10 в bash), настраивает точность и округление, выполняет фактическое деление, делит обратно на соответствующую величину, а затем повторно вставляет десятичную дробь.

Шаг за шагом:

То embiggen() функция присваивает усеченную целочисленную форму своего аргумента $int и сохраняет числа после точки в $fraction. Количество дробных цифр указывается в $precision. Математика умножает 101⁰ на объединение $int и $fraction а затем настраивает его в соответствии с точностью (например embiggen 48.86 становится 101⁰ × 4886 / 100 и возвращает 488600000000 что составляет 488 600 000 000).

Нам нужна конечная точность в сотых долях, поэтому мы умножаем первое число на 100, добавляем 5 для округления, а затем делим второе число. Это назначение $answer оставляет нам в сто раз больший окончательный ответ.

Теперь нам нужно добавить десятичную точку. Мы назначаем новый $int ценность для $answer исключая его последние две цифры, тогда echo это с точкой и $answer исключая $int ценность, о которой уже позаботились. (Не обращайте внимания на ошибку подсветки синтаксиса, из-за которой это выглядит как комментарий)

(Башизм: возведение в степень - это не POSIX, так что это башизм. Чистое решение POSIX потребовало бы циклов для добавления нулей, а не использования степеней десяти. Кроме того, "эмбигген" - это совершенно подходящее слово.)


Одна из главных причин, по которой я использую zsh поскольку моя оболочка такова, что она поддерживает математику с плавающей запятой. Решение этого вопроса довольно простое в zsh:

printf %.2f $((float/1.18))

(Я бы хотел, чтобы кто-нибудь добавил комментарий к этому ответу с помощью хитрости для включения арифметики с плавающей запятой в bash, но я почти уверен, что такой функции еще не существует.)

Я знаю, что это старый вопрос, но у меня есть чистое решение "bc" без "if" или ветвей:

#!/bin/shbcr(){    echo "scale=$2+1;t=$1;scale-=1;(t*10^scale+((t>0)-(t<0))/2)/10^scale" | bc -l}

Используйте его как bcr '2/3' 5 или bcr '0.666666' 2> -- (выражение, за которым следует шкала)

Это возможно, потому что в bc (например, C / C++) разрешено смешивать логические выражения в ваших вычислениях.Выражение ((t>0)-(t<0))/2) будет оцениваться в + /-0,5 в зависимости от знака 't' и, следовательно, использовать правильное значение для округления.

ИМХО, _ никто не ответил на этот вопрос удовлетворительно_, возможно, потому, что bc не может достичь того, что запрашивается (или, по крайней мере, вопрос, который я задавал, когда нашел этот пост), а именно ** как округлять десятичные дроби с помощью bc ** (который, оказывается, вызывается bash).

Я знаю, что этот вопрос устарел, но я не могу удержаться от комментария, подталкивающего мою собственную реализацию bc: GitHub - gavinhoward/bc: An implementation of the POSIX bc calculator with GNU extensions and dc, moved away from GitHub. Finished, but well-maintained. . Для этого он находится во встроенной библиотеке с функцией r(), поэтому вы можете использовать bc -le "r($float/1.18, 2)" .

Я нахожу это странным, потому что “printf “% 0.2f \ n” 41.445” теперь работает, но “printf “% 0.2f \ n” 41.435 и printf “% 0.2f \ n” 41.455” работают. Даже ваш собственный случай работает (на 12.04), но не с .445