Округление до целого числа

Переменная содержит число, не целое к примеру

321.23453

Как данное число округлить до целого, чтобы в дальнейшем выполнить деление на целое.

echo "TEXT $((($time/2))) TEXT"

Попыталась, не выходит. С округлением ничего не понятно, быть может возможно не округляя число выполнить деление на целое?


Ответы (3 шт):

Автор решения: Oopss

Для работы с числами с плавающей точкой, лучше использовать язык программирования. Но для простых вычислений можно использовать терминальный калькулятор 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
→ Ссылка
Автор решения: Pak Uula

Округлить можно встроенными средствами 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

→ Ссылка
Автор решения: Vitalizzare

Во-первых, мы можем отбросить дробную часть, интерпретировав ее как суфикс. В документации это называется 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

→ Ссылка