Быстрый пример того, что я хочу использовать сценарии удара:
#!/bin/bash
echo "Insert the price you want to calculate:"
read float
echo "This is the price without taxes:"
echo "scale=2; $float/1.18" |bc -l
read -p "Press any key to continue..."
bash scriptname.sh
Предположение, что цена: 48.86 Ответ будет be:41.406779661 (41.40 на самом деле, потому что я использую scale=2;
)
Мой Вопрос: Как я вокруг второго десятичного числа для показа ответа таким образом?: 41.41
Удар круглая функция:
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 float
echo "This is the price without taxes:"
#echo "scale=2; $float/1.18" |bc -l
echo $(round $float/1.18 2);
read -p "Press any key to continue..."
Удача: o)
Простое решение:
printf %.2f $(echo "$float/1.18" | bc -l)
Округление 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 <<MATH
h=0
scale=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.5
if (m > 0) h=0.5
a=(m * t + h)
scale=$result_scale
a / t
MATH
#!/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 float
echo "This is the price without taxes:"
round2 $float 1.18 2
echo && read -p "Press any key to continue..."
Это на самом деле просто: нет никакой потребности явно добавить hardcoded "-0.5" вариант для отрицательных чисел. Математически говоривший, мы просто вычислим , абсолютное значение аргумента и все еще добавляет 0.5, как мы обычно были бы. Но так как у нас (к сожалению), нет встроенного abs()
функция в нашем распоряжении (если мы не кодируем один), мы будем просто инвертировать аргумент, если это будет отрицательно.
Кроме того, это оказалось очень громоздким для работы с частное в качестве параметра (так как для моего решения, я должен смочь получить доступ к дивиденду и делителю отдельно). Поэтому мой сценарий имеет дополнительный третий параметр.
Я знаю, что это - старый вопрос, но у меня есть чистое 'до н.э '-решение без 'если' или ответвления:
#!/bin/sh
bcr()
{
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
-> (выражение, сопровождаемое масштабом)
, Это возможно, потому что в до н.э (как C/C++) это позволяется смешиванию логических выражений в Ваших вычислениях. Выражение ((t>0)-(t<0))/2)
будет оценивать к +/-0.5 в зависимости от знака 't' и поэтому использовать правильное значение для округления.
если Вы имеете результат, например, рассматриваете 2.3747888
все, что необходимо сделать:
d=$(echo "(2.3747888+0.5)/1" | bc); echo $d
это округляет число правильно пример:
(2.49999 + 0.5)/1 = 2.99999
десятичные числа удалены bc
и таким образом, это округляет в меньшую сторону до 2, как это должно иметь
Я все еще ищу чистое bc
ответьте на то, как к раунду всего одно значение в функции, но вот чистое bash
ответ:
#!/bin/bash
echo "Insert the price you want to calculate:"
read float
echo "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 negative
if [ "$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 integer
echo $int.${answer#$int} # reassemble with correct precision
read -p "Press any key to continue..."
В основном это тщательно извлекает десятичные числа, умножает все на 100 миллиардов (10 ¹ ⁰, 10**10
в bash
), корректируется для точности и округления, выполняет фактическое подразделение, делится назад к соответствующей величине и затем повторно вставляет десятичное число.
Пошаговый:
embiggen()
функция присваивает усеченную целочисленную форму своего аргумента $int
и сохраняет числа после точки в $fraction
. Количество дробных цифр отмечено в $precision
. Математика умножает 10 ¹ ⁰ на конкатенацию $int
и $fraction
и затем корректирует это для соответствия точности (например. embiggen 48.86
становится 10 v × 4886 / 100 и возвраты 488600000000
который является 488,600,000,000).
Мы хотим заключительную точность сотых частей, таким образом, мы умножаем первое число на 100, добавьте 5 для округления целей и затем разделите второе число. Это присвоение $answer
оставляет нас в сто раз окончательном ответе.
Теперь мы должны добавить десятичную точку. Мы присваиваем новое $int
значение к $answer
исключая его заключительные две цифры, затем echo
это с точкой и $answer
исключая $int
значение это уже заботилось о. (Не берите в голову ошибку подсветки синтаксиса, которая заставляет это появиться как комментарий),
(Bashism: возведением в степень не является POSIX, таким образом, это - bashism. Чистое решение POSIX потребовало бы, чтобы циклы добавили нули вместо того, чтобы использовать полномочия десять. Кроме того, "embiggen" отлично cromulant слово.)
Одна из главных причин я использую zsh
поскольку моя оболочка - то, что это поддерживает математические операции с плавающей точкой. Решение этого вопроса довольно просто в zsh
:
printf %.2f $((float/1.18))
(Я хотел бы видеть, что кто-то добавляет комментарий к этому ответу с приемом к включению арифметики с плавающей точкой в bash
, но я вполне уверен, что такая функция еще не существует.)
Я должен был вычислить общую продолжительность набора звуковых файлов.
, Таким образом, я имел к:
А получают продолжительность для каждого файла ( не показанный )
, B. складывают все продолжительности (они были каждым в NNN.NNNNNN
(fp) секунды)
C. отдельные часы, минуты, секунды, подсекунды.
D. производят строку HR:MIN:SEC:FRAMES, где кадр = 1/75 секунда.
(Кадры прибывают из кода SMPTE, используемого в студиях.)
<час> А: используйте ffprobe
и проанализируйте строку продолжительности в fp номер (не показанный)
B:
# add them up as a series of strings separated by "+" and send it to bc
arr=( "${total[@]}" ) # copy array
# IFS is "Internal Field Separator"
# the * in arr[*] means "all of arr separated by IFS"
# must have been made for this
IFS='+' sum=$(echo "scale=3; ${arr[*]} "| bc -l)# (-l= libmath for fp)
echo $sum
C:
# subtract each amount of time from tt and store it
tt=$sum # tt is a running var (fp)
hrs=$(echo "$tt / 3600" | bc)
tt=$(echo "$tt - ( $hrs * 3600 )" | bc )
min=$(echo "$tt / 60" | bc )
tt=$(echo "$tt - ($min *60)" | bc )
sec=$(echo "$tt/1" | bc )
tt=$(echo "$tt - $sec" | bc )
frames=$(echo "$tt * 75" | bc ) # 75 frames /sec
frames=$(echo "$frames/1" | bc ) # truncate to whole #
D:
#convert to proper format with printf (bash builtin)
hrs=$(printf "%02d\n" $hrs) # format 1 -> 01
min=$(printf "%02d\n" $min)
sec=$(printf "%02d\n" $sec)
frames=$(printf "%02d\n" $frames)
timecode="$hrs:$min:$sec:$frames"
# timecode "01:13:34:54"
Можно использовать awk, никакие необходимые каналы:
$> PRICE=48.86
$> awk -vprice=$PRICE "BEGIN{printf(\"%.2f\n\",price/1.18+0.005)}"
41.41
Установите цену заранее с переменной среды PRICE=<val>
.
Затем назовите awk - $PRICE
войдет в awk как в awk переменную price
.
Это затем окружено к ближайшему 100-му с +.005.
printf параметр форматирования %.2f
ограничивает масштаб двумя десятичными разрядами.
Если необходимо сделать, этот много этого пути намного более эффективен, чем выбранный ответ:
time for a in {1..1000}; do echo $(round 48.86/1.18 2) > /dev/random; done
real 0m8.945s
user 0m6.067s
sys 0m4.277s
time for a in {1..1000}; do awk -vprice=$PRICE "BEGIN{printf(\"%.2f\n\",price/1.18+0.005)}">/dev/random; done
real 0m2.628s
user 0m1.462s
sys 0m1.275s
Вот сокращенная версия Вашего сценария, исправленного для обеспечения вывода, который Вы хотите:
#!/bin/bash
float=48.86
echo "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/rate
scale=3; p3=float/rate
scale=4; p4=float/rate
print "Compare: ",p2, " v ", p3, " v ", p4
Compare: 41.40 v 41.406 v 41.4067
# however, scale does not affect an entered value (nor addition)
scale=0
a=.005
9/10
0
9/10+a
.005
# let's try rounding
scale=2
p2+a
41.405
p3+a
41.411
(p2+a)/1
41.40
(p3+a)/1
41.41
Чистый до н.э реализация согласно просьбе
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
Код для до н.э реализации найден на http://phodd.net/gnu-bc/code/funcs.bc
bc() {
while :
do
while IFS='$\n' read i
do
/usr/bin/bc <<< "scale=2; $i" | sed 's/^\./0&/'
done
done
}
PRINTF НЕ НАДЕЖЕН:
Метод printf очень удобен, прост в использовании и описан во множестве инструкций.
Однако, если вы жестко закодировали десятичную точку, вы должны знать, что ваш код, вероятно, не будет работать, если используется одна из многих стран, в которых используется разделитель-запятая.
Удивительно много стран действительно используют это, и многие из них в Европе. Наверное, столько же, сколько используют точку. Согласно Wikipedia > Decimal_separator, запятая отмечена как директива ISO/IEC...
Вот что происходит, если на вашем компьютере установлена система счисления для использования запятых:
printf %.2f 573,5489
573,55
но
printf %.2f 573.5489
printf: 573.5489: invalid number
Как нам обойти это ?
Использование 'bc' является одним из способов.Сам по себе, просто с масштабом = n. Его не нужно передавать по конвейеру, как в некоторых примерах. Помните, что шкала работает только при делении и делении введенной суммы на единицу. См. ответ пользователя @user525061
. Другой вариант, особенно если у вас уже есть код, использующий метод printf, может заключаться в изменении локали сеанса оболочки с помощью «экспорта».
Попробуйте:
export LC_NUMERIC=C
Но тогда это сводит на нет простоту printf....