Округление до целого числа
Переменная содержит число, не целое к примеру
321.23453
Как данное число округлить до целого, чтобы в дальнейшем выполнить деление на целое.
echo "TEXT $((($time/2))) TEXT"
Попыталась, не выходит. С округлением ничего не понятно, быть может возможно не округляя число выполнить деление на целое?
Ответы (3 шт):
Для работы с числами с плавающей точкой, лучше использовать язык программирования. Но для простых вычислений можно использовать терминальный калькулятор bc.
apt install bc (или как в вашем пакетном менеджере)
echo "Text $(echo "scale=2; 321.2345/2"|bc) Next next"
Text 160.61 Next next
Если нужно целое, но это без округления,
echo "Text $(echo "scale=0; 321.2345/2"|bc) Next next"
Text 160 Next next
Если с округлением до ближайшего целого
echo "Text $(echo "scale=0; (321.2345 / 2 + 0.5) / 1"|bc) Next next"
Text 160 Next next
Округлить можно встроенными средствами bash
. Функция printf
при печати вещественных чисел с заданной точностью округляет перед печатью:
NUM=34.567
ROUNDED=$(printf "%.0f" $NUM)
echo $ROUNDED
Напечатает 35
Но делить bash умеет только нацело: echo $(( 35 / 2 ))
выдает 17.
Для деления нужно пользоваться сторонними программами, таким как bc
# Принимает три параметра A B NUM_DIGS
# Печатает A/B с числом NUM_DIGS цифр после запятой
# Если NUM_DIGS не задано, то равно 6.
function div {
a=$1
b=$2
num_digs=${3:-6}
echo "scale=$num_digs; $a / $b" | bc
}
Полный пример, 321.23453
округляем и делим на 4
:
function round {
a=$1
printf "%.0f\n" $a
}
function div {
a=$1
b=$2
num_digs=${3:-6}
echo "scale=$num_digs; $a / $b" | bc
}
TEST=321.23453
OTHER=4
echo $(div $(round $TEST) $OTHER 3)
Результат 80.250
Во-первых, мы можем отбросить дробную часть, интерпретировав ее как суфикс. В документации это называется Parameter Expansion. Аналогично, чтобы взять дробную часть, мы интерпретируем целую часть числа до точки включительно как префикс. Например:
x=12.345; echo "x=$x, int(x)=${x%.*}, frac(x)=${x#*.}"
Результатом этого кода будет строка "x=12.345, int(x)=12, frac(x)=345"
.
А если мы работаем в Bash, то можем сохранить дробную часть, заменив точку пробелом и взяв результат в скобки. Это будет интерпретировано как массив. При обращении к переменной по имени без указания индекса будет использовано первое значение массива (т.е. целая часть в нашем случае). А если понадобиться дробная, то мы достаем ее из числа явно указав индекс 1:
x=12.345
number=(${x/./" "}) # это замена точки на пробел, двойные кавычки
# не обязательны, они для того, чтобы явно обозначить
# присутствие пробела и облегчить чтение кода
echo "number=$number, frac(number)=${number[1]}"
Результатом этого кода будет строка "number=12, frac(number)=345"
.
При желании, можем округлить, извлекая первую цифру дробной части, разделив ее на 5 и добавив результат к целой части (здесь ${frac_x:0:1}
значит извлечь из frac_x
подстроку единичной длинны начиная с позиции 0):
x=34.567; frac_x=${x#*.}; round_x=$((${x%.*} + ${frac_x:0:1}/5)); echo $round_x
Результатом этого кода будет число 35.
P.S. Судя по комментариям, вы хотите обработать время, возвращаемое командой
ffprobe -i file_path -show_entries format=duration -v quiet -of csv=p=0
Это время указано в секундах. Предположу, что вы хотите представить его в формате hh:mm:ss.ms
Для этой цели я бы использовал awk
:
ffprobe -i video.mp4 -show_entries format=duration -v quiet -of csv=p=0 | \
awk '{t=$1; h=int(t/3600); m=int(t/60)%60; s=t%60;
printf "%02i:%02i:%02.3f\n", h, m, s}'
Если возвращаемое время равно 321.23453
, то результат вышеуказанного кода будет 00:05:21.235
(т.е. продолжительность видео равна 5 минут и 21 секунда с хвостиком)
См. также: Об особенностях округления в Awk