Как преобразовать число с плавающей точкой в целое число?

Группы процесса установлены программой, которая изменяется от корня до целевого пользователя прежде, чем выполнить программу процесса. Когда пользователь входит в систему, программа, которая изменяет пользователя, является программой входа в систему (login, su, sshd, …), и программа процесса является оболочкой пользователя. Для демона, выполненного при пользователе системы, программа, которая изменяет пользователя, может быть su или некоторый другой инструмент, такой как Debian start-stop-daemon. Например, start-stop-daemon всегда добавляет дополнительные группы к процессу. Изменяющая пользователя программа должна иметь логику для установки и основной группы от пользовательской базы данных и дополнительной группы от базы данных группы.

49
31.10.2019, 15:24
5 ответов

удар

В bash, это, вероятно, так хорошо, как это добирается. Это использует встроенную оболочку. При необходимости в результате в переменной Вы могли бы использовать замену команды, или bash конкретный (хотя теперь также поддерживается zsh):

printf -v int %.0f "$float"

Вы могли сделать:

float=1.23
int=${float%.*}

Но это удалило бы дробную часть вместо того, чтобы дать Вам ближайшее целое число, и это не будет работать на значения $float как 1.2e9 или .12 например.

Также отметьте возможные ограничения из-за внутреннего представления плаваний:

$ printf '%.0f\n' 1e50
100000000000000007629769841091887003294964970946560

Вы действительно получаете целое число, но возможности состоят в том, что Вы не сможете использовать то целое число где угодно.

Кроме того, как отмечено @BinaryZebra, в нескольких printf реализации (удар, ksh93, yash, не GNU, zsh, тире), это затронуто локалью (десятичный разделитель, который может быть . или ,).

Так, если Ваши плавания всегда выражаются периодом как десятичный разделитель, и Вы хотите, чтобы он рассматривался как таковой printf независимо от локали пользователя, вызывающего Ваш сценарий, необходимо было бы прикрепить локаль к C:

LC_ALL=C printf '%.0f' "$float"

С yash, можно также сделать:

printf '%.0f' "$(($float))"

(см. ниже).

POSIX

printf "%.0f\n" 1.1

не POSIX как %f не требуется, чтобы поддерживаться POSIX.

POSIXly, можно сделать:

f2i() {
  awk 'BEGIN{for (i=1; i<ARGC;i++)
   printf "%.0f\n", ARGV[i]}' "$@"
}

Тот не затронут локалью (запятая не может быть десятичным разделителем в awk так как это уже - специальный символ в синтаксисе там (print 1,2, то же как print 1, 2 передать два аргумента print)

zsh

В zsh (который поддерживает арифметику с плавающей точкой (десятичный разделитель всегда является периодом)), Вы имеете rint() математическая функция, чтобы дать Вам ближайшее целое число как плавание (как в C) и int() дать Вам целое число от плавания (как в awk). Таким образом, можно сделать:

$ zmodload zsh/mathfunc
$ i=$((int(rint(1.234e2))))
$ echo $i
123

Или:

$ integer i=$((rint(5.678e2)))
$ echo $i
568

Однако отметьте это в то время как doubles может представить очень большие количества, целые числа намного более ограничены.

$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808

ksh93

ksh93 был первой подобной Границе оболочкой, которая будет поддерживать арифметику с плавающей точкой. ksh93 оптимизирует замену команды, не используя канал или разветвляясь, когда команды являются только встроенными командами. Так

i=$(printf '%.0f' "$f")

не разветвляется. Или еще лучше:

i=${ printf '%.0f' "$f"; }

который не разветвляет ни одного, но также и не идет вся проблема создать поддельную подсреду оболочки.

Можно также сделать:

i=$((rint(f)))

Но остерегайтесь:

$ echo "$((rint(1e18)))"
1000000000000000000
$ echo "$((rint(1e19)))"
1e+19

Вы могли также сделать:

integer i=$((rint(f)))

Но как для zsh:

$ integer i=1e18
$ echo "$i"
1000000000000000000
$ integer i=1e19
$ echo "$i"
-9223372036854775808

Остерегайтесь этого ksh93 арифметика с плавающей точкой соблюдает десятичную установку разделителя в локали (даже при том, что , иначе математический оператор ($((1,2)) был бы 6/5 во французах/Немце... локаль и то же как $((1, 2)), это 2 в английской локали).

yash

yash также поддерживает арифметику с плавающей точкой, но не имеет математических функций как ksh93/zsh rint(). Можно преобразовать число в целое число, хотя при помощи двоичного файла или оператора, например (также работает в zsh но не в ksh93). Обратите внимание однако, что это усекает десятичную часть, это не дает Вам ближайшее целое число:

$ echo "$((0.237e2 | 0))"
23
$ echo "$((1e19))"
-9223372036854775808

yash соблюдает десятичный разделитель локали на выводе, но не для литеральных констант с плавающей точкой в его арифметических выражениях, которые могут вызвать неожиданности:

$ LC_ALL=fr_FR.UTF-8 ./yash -c 'a=$((1e-2)); echo $(($a + 1))'
./yash: arithmetic: `,' is not a valid number or operator

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

var=$((10.3)) # and not var=10.3
... "$((a + 0.1))" # and not "$(($a + 0.1))".

printf '%.0f\n' "$((10.3))" # and not printf '%.0f\n' 10.3
73
27.01.2020, 19:33

bc - Язык калькулятора произвольной точности

интервал (плавание) должен быть похожим:

$ echo "$float/1" | bc 
1234

К круглому лучше используют это:

$ echo "($float+0.5)/1" | bc 

Пример:

$ float=1.49
$ echo "($float+0.5)/1" | bc 
1
$ float=1.50
$ echo "($float+0.5)/1" | bc 
2
22
27.01.2020, 19:33

Очень простой способ взлома -

function float_to_int() { 
  echo $1 | cut -d. -f1    # or use -d, if decimals separator is ,
}

Пример вывода

$ float_to_int 32.333
32
$ float_to_int 32
32
3
27.01.2020, 19:33

Предыдущий ответ был почти правильным: «Вы могли бы сделать:

float=1.23
int=${float%.*}

Но это удалило бы дробную часть вместо того, чтобы дать вам ближайшее целое число и это не будет работать для значений $ float, например, 1.2e9 или .12 .... "

Просто используйте $ {float %%. *} .

echo ${float%%.*}
1
5
27.01.2020, 19:33

Похожие:

  1. как преобразовать число с плавающей запятой в целое число в awk ,
  2. Как округлить числа с плавающей запятой в оболочке?

Дополнение @Stéphane Chazelasawkответ:

float_to_integer_rounding_nearst() {
    awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%.0f", ARGV[i]}' "$@";
}

float_to_integer_rounding_floor() {
    awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%d", int( ARGV[i] )}' "$@";
}
1
27.01.2020, 19:33

Теги

Похожие вопросы