Un exemple rapide de ce que je veux utiliser les scripts bash:
#!/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
En supposant que le prix est: 48.86 La réponse sera: 41.406779661 (41.40 en fait car j'utilise scale=2;
)
Ma question est: Comment puis-je arrondir la deuxième décimale pour afficher la réponse de cette manière?: 41.41
Une fonction bash round:
round()
{
echo $(printf %.$2f $(echo "scale=$2;(((10^$2)*$1)+0.5)/(10^$2)" | bc))
};
Utilisé dans votre exemple de code:
#!/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..."
Bonne chance: o)
La solution la plus simple:
printf %.2f $(echo "$float/1.18" | bc -l)
Bash/awk arrondi:
echo "23.49" | awk '{printf("%d\n",$1 + 0.5)}'
Si vous avez python, vous pouvez utiliser quelque chose comme ceci:
echo "4.678923" | python -c "print round(float(raw_input()))"
Voici une solution purement bc. Règles d'arrondi: à +/- 0,5, arrondir à zéro.
Mettez la balance que vous cherchez dans $ result_scale; votre calcul devrait être où $ MATH est situé dans la liste de commande bc:
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
Je sais que c'est une vieille question, mais j'ai une solution pure 'bc' sans 'if' ou branches:
#!/bin/sh
bcr()
{
echo "scale=$2+1;t=$1;scale-=1;(t*10^scale+((t>0)-(t<0))/2)/10^scale" | bc -l
}
Utilisez-le comme bcr '2/3' 5
ou bcr '0.666666' 2
-> (expression suivie d'une échelle)
C'est possible parce qu'en bc (comme C/C++), il est permis de mélanger des expressions logiques dans vos calculs. L'expression ((t>0)-(t<0))/2)
sera évaluée à +/- 0.5 en fonction du signe de 't' et utilisera donc la bonne valeur pour l'arrondi.
Je devais calculer la durée totale d'une collection de fichiers audio.
Donc je devais:
A. obtenir la durée de chaque fichier (non affiché)
B. additionnez toutes les durées (elles étaient chacune en NNN.NNNNNN
(fp) secondes)
C. séparez les heures, les minutes, les secondes, les sous-secondes.
D. sort une chaîne de HR: MIN: SEC: FRAMES, où frame = 1/75 sec.
(Les cadres proviennent du code SMPTE utilisé dans les studios.)
A: utilisez ffprobe
et la ligne de durée d'analyse dans un numéro fp (non affiché)
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 #
RÉ:
#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"
Pure BC implémentation à la demande
define ceil(x) { auto os,xx;x=-x;os=scale;scale=0 xx=x/1;if(xx>x).=xx-- scale=os;return(-xx) }
si vous mettez cela dans un fichier appelé functions.bc, alors vous pouvez arrondir avec
echo 'ceil(3.1415)' | bc functions.bc
Code pour l'implémentation bc trouvé sur http://phodd.net/gnu-bc/code/funcs.bc
Je cherche toujours une pure réponse bc
pour savoir comment arrondir une seule valeur dans une fonction, mais voici une pure réponse bash
name__:
#!/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..."
Fondamentalement, ceci extrait soigneusement les décimales, multiplie le tout par 100 milliards (10¹⁰, 10**10
in bash
name__), ajuste la précision et l’arrondi, effectue la division réelle, divise à nouveau la magnitude appropriée, puis réinsère la décimale.
Pas à pas:
La fonction embiggen()
affecte la forme entière tronquée de son argument à $int
et enregistre les nombres après le point dans $fraction
. Le nombre de chiffres fractionnaires est noté dans $precision
. Le calcul multiplie 10¹⁰ par la concaténation de $int
et $fraction
, puis ajuste cela pour correspondre à la précision (par exemple, embiggen 48.86
devient 10¹⁰ × 4886/100 et renvoie 488600000000
, qui est 488,600,000,000).
Nous voulons une précision finale de centièmes. Nous multiplions donc le premier nombre par 100, en ajoutons 5 aux fins de l'arrondi, puis nous divisons le deuxième nombre. Cette assignation de $answer
nous laisse cent fois la réponse finale.
Nous devons maintenant ajouter le point décimal. Nous attribuons une nouvelle valeur $int
à $answer
en excluant ses deux derniers chiffres, puis echo
avec un point et le $answer
en excluant la valeur $int
déjà prise en charge. (Peu importe le bug de mise en évidence de la syntaxe qui le fait apparaître comme un commentaire)
(Bashism: l’exponentiation n’est pas POSIX, c’est donc un penchant. Une solution POSIX pure nécessiterait des boucles pour ajouter des zéros plutôt que d’utiliser des puissances de dix. En outre, "embiggen" est un mot parfaitement cromulant.)
L'une des principales raisons pour lesquelles j'utilise zsh
en tant que mon shell est qu'il prend en charge les mathématiques en virgule flottante. La solution à cette question est assez simple dans zsh
name__:
printf %.2f $((float/1.18))
(J'adorerais voir quelqu'un ajouter un commentaire à cette réponse en essayant d'activer l'arithmétique en virgule flottante dans bash
name__, mais je suis à peu près sûr qu'une telle fonctionnalité n'existe pas encore.)
si vous avez le résultat, considérez par exemple 2.3747888
tout ce que tu dois faire est:
d=$(echo "(2.3747888+0.5)/1" | bc); echo $d
ceci arrondit correctement le nombre, par exemple:
(2.49999 + 0.5)/1 = 2.99999
les décimales sont supprimées par bc
et se réduit donc à 2 comme il se doit
#!/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..."
C'est en fait simple: il n'est pas nécessaire d'ajouter explicitement une variante "-0.5" codée en dur pour les nombres négatifs. Mathématiquement parlant, nous allons simplement calculer le valeur absolue de l'argument et toujours ajouter 0.5 comme nous le ferions normalement. Mais comme nous n’avons (malheureusement) pas de fonction abs()
intégrée (sauf si nous en codons une), nous allons simplement nier l’argument s’il est négatif.
De plus, travailler avec le quotient en tant que paramètre ((pour ma solution, je dois pouvoir accéder séparément au dividende et au diviseur) s'est avéré très fastidieux). . C'est pourquoi mon script a un troisième paramètre supplémentaire.
Voici une version abrégée de votre script, corrigée pour fournir le résultat souhaité:
#!/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
Notez que arrondir au nombre entier le plus proche équivaut à ajouter 0,5 et prendre la parole, ou arrondir à la baisse (pour les nombres positifs).
En outre, le facteur d'échelle est appliqué au moment de l'opération; alors (ce sont des commandes bc
name__, vous pouvez les coller dans votre terminal):
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
bc() {
while :
do
while IFS='$\n' read i
do
/usr/bin/bc <<< "scale=2; $i" | sed 's/^\./0&/'
done
done
}