कैसे bash में bc का उपयोग करके गोल दशमलव करें?


45

बैश स्क्रिप्टिंग का उपयोग करके मैं जो चाहता हूं उसका एक त्वरित उदाहरण:

#!/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 उत्तर होगा: 41.406779661 (41.40 वास्तव में क्योंकि मैं उपयोग कर रहा हूं scale=2;)

मेरा प्रश्न है: मैं इस तरह से उत्तर दिखाने के लिए दूसरे दशमलव को कैसे गोल करूंगा ?: 41.41


मुझे यह अजीब लगता है क्योंकि "printf"% 0.2f \ n "41.445" अब काम करता है लेकिन "printf"% 0.2f \ n "41.435 और printf"% 0.2f \ n "41.455" करते हैं। यहां तक ​​कि आपका अपना मामला काम करता है (12.04 पर) लेकिन .445 के साथ नहीं
लुइस

8
IMHO, किसी ने भी इस प्रश्न का संतोषजनक उत्तर नहीं दिया , शायद इसलिए bcकि जो प्राप्त किया जा रहा है उसे प्राप्त नहीं किया जा सकता है (या कम से कम वह प्रश्न जो मैं इस पोस्ट को पाते समय पूछ रहा था), जो कि कैसेbc (जिसे कहा जाता है bash) का उपयोग करके गोल गोल करना है ।
एडम काट्ज

मुझे पता है कि यह सवाल पुराना है, लेकिन मैं bc: github.com/gavinhoward/cc के अपने कार्यान्वयन को आगे बढ़ाने वाली टिप्पणी का विरोध नहीं कर सकता । उसके लिए, यह r()फ़ंक्शन के साथ अंतर्निहित लाइब्रेरी में है, इसलिए आप उपयोग कर सकते हैं bc -le "r($float/1.18, 2)"
गैविन हॉवर्ड

जवाबों:


31

एक बश दौर समारोह:

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..."

सौभाग्य: ओ)


1
btw, यदि संख्या नकारात्मक है, तो हमें उपयोग करना होगा-0.5
कुंभ राशि

परीक्षण कंसोल पर काम करने के लिए उदाहरण नहीं मिल सका! "डीबगिंग" से पता चला कि उदाहरण के लिए $2 = 3मुझे इस्तेमाल करना था echo $(env printf %.3f $(echo "scale=3;((1000*$1)+0.5)/1000" | bc))प्रिंट से पहले एनवीवी का मन करें ! यह आपको फिर से सिखाएगा कि यह समझना हमेशा महत्वपूर्ण है कि आप कहीं और से कॉपी-पेस्ट कर रहे हैं।
वाक्य रचना

@Aquarius पावर प्रेरणा के लिए धन्यवाद! मैंने अब उपरोक्त स्क्रिप्ट का एक संस्करण कांटा है जो नकारात्मक और सकारात्मक दोनों संख्याओं के साथ काम करेगा।
वाक्य रचना

यह अनावश्यक रूप से जटिल है और सभी प्रकार के अतिरिक्त अंकगणित को मिगस और ज़ुबाउबेर द्वारा प्रदान किए गए सरल उत्तरों पर पहुंचने के लिए करता है।
एडम काट्ज़

@AquariusPower +1 हां, यह नकारात्मक संख्याओं के लिए अलग है। एक ऋणात्मक (गैर पूर्णांक!) संख्या के लिए परीक्षण करने के लिए, मैंने थोड़ी कोशिश की और if [ प्रतिध्वनि "$ 1/1" के लिए सुलझा ली । bc` -gt 0] `- जांच करने के लिए एक और अधिक सुरुचिपूर्ण तरीका है (" - "के लिए स्ट्रिंग को छोड़कर)?
रॉबर्टजी

30

सबसे सरल समाधान:

printf %.2f $(echo "$float/1.18" | bc -l)

2
जैसा कि ऊपर एक टिप्पणी में भी कहा गया है ( askubuntu.com/a/179949/512213 ), यह दुर्भाग्य से नकारात्मक संख्या के लिए गलत व्यवहार करेगा।
राबर्ट 16:

2
@ रोबर्ट जी: क्यों? इस समाधान का उपयोग नहीं करता है +0.5। प्रयास करें printf "%.2f\n" "$(bc -l <<<"48.86/1.18")" "$(bc -l <<<"-48.86/1.18")"और आप मिल जाएगा 41.41और -41.41
मुसीफिल

1
पाइप का उपयोग करना भी संभव है:echo "$float/1.18" | bc -l | xargs printf %.2f
मिठाई

इस उत्तर में समाधान मुझे देता है: bash: printf: 1.69491525423728813559: invalid numberलोकेल पर निर्भर करता है।
टॉर्स्टन ब्रॉन्जर

19

बैश / जाग चक्कर

echo "23.49" | awk '{printf("%d\n",$1 + 0.5)}'  

यदि आपके पास अजगर है तो आप इस तरह से कुछ का उपयोग कर सकते हैं:

echo "4.678923" | python -c "print round(float(raw_input()))"

टिप के लिए धन्यवाद, लेकिन यह हल नहीं है कि मुझे क्या चाहिए। मुझे इसे बस बैश का उपयोग करके करना है ...
ब्लैकडेक्स

1
अजगर कमांड अधिक पठनीय है और त्वरित स्क्रिप्ट के लिए अच्छा है। साथ ही, राउंड फंक्शन में ", 3" जैसे जोड़कर मनमाना डिजिट राउंडिंग का समर्थन करता है। साभार
एले

echo "$float" |awk '{printf "%.2f", $1/1.18}'प्रश्न के अनुरोधित गणित को शत-प्रतिशत करने का अनुरोध करेगा। यह bcप्रश्न में कॉल के रूप में "बैश का उपयोग" जितना है ।
एडम काट्ज़

2
पायथन के लिए आप बस कुछ ऐसा इस्तेमाल कर सकते हैं python -c "print(round($num))"जहां num=4.678923। स्टड के साथ के बारे में पिघलने की कोई जरूरत नहीं है। आप भी इस तरह n अंक के लिए गोल कर सकते हैं python -c "print(round($num, $n))":।
छह

मैं उस समाधान के साथ कुछ साफ सुथरा करने में कामयाब रहा, मेरी समस्या 0.5 थी, इस मामले में मुझे हमेशा वह राउंड नहीं मिला जिसकी मुझे ज़रूरत थी इसलिए मैं निम्नलिखित के साथ आया: echo 5 | python -c "print int(round((float(raw_input())/2)-0.5))"(जब + राउंड अप और - राउंड डाउन होगा)।
यार्न

4

यहाँ एक शुद्ध ई.पू. समाधान है। गोलाई के नियम: +/- 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

1
बहुत ही रोचक! MATH=-0.34;result_scale=1;bc <<MATH, #OjectiveAndClear: 5 जैसा कि यहां बताया गया है :)
कुंभ राशि पावर

मैं इसे "सर्वश्रेष्ठ उत्तर" के लिए नामांकित करता हूं।
मार्क टैम्स्की

2

मुझे पता है कि यह एक पुराना सवाल है, लेकिन मेरे पास 'if' या शाखाओं के बिना शुद्ध 'bc'-solution है:

#!/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-> (पैमाने के बाद अभिव्यक्ति)

यह संभव है क्योंकि बीसी (सी / सी ++ की तरह) यह आपकी गणना में तार्किक अभिव्यक्तियों को मिश्रण करने की अनुमति देता है। अभिव्यक्ति ((t>0)-(t<0))/2)'t' के संकेत के आधार पर +/- 0.5 का मूल्यांकन करेगी और इसलिए गोलाई के लिए सही मान का उपयोग करेगी।


यह साफ-सुथरा दिखता है, लेकिन बदले में bcr "5 / 2" 0लौटता 2है 3। क्या मैं कुछ भूल रहा हूँ?
ब्‍लूजय

1
#!/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..."

यह वास्तव में सरल है: नकारात्मक संख्याओं के लिए स्पष्ट रूप से हार्डकोड "-0.5" संस्करण जोड़ने की आवश्यकता नहीं है। गणितीय रूप से बोला गया है, हम केवल तर्क के निरपेक्ष मान की गणना करेंगे और फिर भी 0.5 जोड़ देंगे जैसा कि हम सामान्य रूप से करते हैं। लेकिन चूंकि हमारे पास (दुर्भाग्य से) abs()हमारे निपटान में कोई अंतर्निहित कार्य नहीं है (जब तक कि हम एक कोड नहीं करते हैं), हम केवल नकारात्मक होने पर तर्क को नकार देंगे ।

इसके अलावा, यह एक पैरामीटर के रूप में भागफल के साथ काम करने के लिए बहुत बोझिल साबित हुआ (क्योंकि मेरे समाधान के लिए, मुझे लाभांश और विभाजक को अलग-अलग एक्सेस करने में सक्षम होना चाहिए)। यही कारण है कि मेरी स्क्रिप्ट में एक अतिरिक्त तीसरा पैरामीटर है।


@ अपने हालिया संपादन के बारे में: बजाए इसके echo .. |, शैल अंकगणित, इसके बारे में क्या है echo $()? यह समझाना आसान है: आपके यहाँ तार हमेशा एक लेखन योग्य/tmp निर्देशिका की आवश्यकता होगी ! और मेरे समाधान भी केवल पढ़ने के लिए पर्यावरण, जैसे एक आपातकालीन जड़ खोल जहां पर काम करेंगे /है नहीं हमेशा डिफ़ॉल्ट रूप से लिखने योग्य। इसलिए एक अच्छा कारण था कि मैंने इसे इस तरह से कोडित किया।
वाक्यविन्यास

Herestrings, मैं सहमत हूँ। लेकिन echo $()कभी ज़रूरत कब पड़ती है? उस और इंडेंटेशन ने मेरे संपादन को प्रेरित किया, चरवाहे बस हो गए।
मूरू

@ मुरू खैर उस समय का सबसे व्यर्थ मामला echo $()तय होने के लिए अतिदेय था, वास्तव में प्रचलित रेखा, लोल। सर उठाने के लिए धन्यवाद। कम से कम यह अब बहुत बेहतर दिखता है, मैं इनकार नहीं कर सकता। वैसे भी, मुझे इसमें तर्क बहुत पसंद था। बूलियन सामान के बहुत कम, कम "अगर" (जो निश्चित रूप से कोड को 50 प्रतिशत तक उड़ा देगा)।
वाक्यविन्यास

1

मैं अभी भी एक शुद्ध 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 100 10**10इंच bash) से गुणा करता है, सटीक और गोलाई के लिए समायोजित करता है, वास्तविक विभाजन करता है, उचित परिमाण में वापस विभाजित करता है, और फिर दशमलव को पुन: स्थापित करता है।

क्रमशः:

embiggen()समारोह प्रदान करती है करने के लिए अपने तर्क के रूप पूर्णांक छोटा कर दिया $intऔर में डॉट के बाद संख्या की बचत होती है $fraction। भिन्नात्मक अंकों की संख्या में नोट किया गया है $precision। गणित पलता 10¹⁰ के संयोजन से $intऔर $fractionऔर फिर समायोजित कर देता है कि सटीक मैच के लिए (जैसे embiggen 48.8610¹⁰ × 4886/100 और रिटर्न हो जाता है 488600000000जो 488,600,000,000 है)।

हम सौवें की एक अंतिम परिशुद्धता चाहते हैं, इसलिए हम पहले नंबर को 100 से गुणा करते हैं, गोलाई के उद्देश्यों के लिए 5 जोड़ते हैं, और फिर दूसरे नंबर को विभाजित करते हैं। का यह काम $answerएक सौ गुना अंतिम जवाब में हमें पत्ते।

अब हमें दशमलव बिंदु जोड़ने की आवश्यकता है। हम इसके अंतिम दो अंकों $intको $answerछोड़कर एक नया मान प्रदान करते हैं , फिर echoयह एक बिंदु और पहले से ध्यान $answerरखे गए $intमूल्य को छोड़कर । (कभी भी सिंटैक्स हाइलाइटिंग बग पर ध्यान न दें जो इसे एक टिप्पणी की तरह दिखाई देता है)

(बैशिज़्म: एक्सपोज़रिएशन POSIX नहीं है, इसलिए यह बैशिज़्म है। एक शुद्ध POSIX सॉल्यूशन के लिए दस की शक्तियों का उपयोग करने के बजाय शून्य जोड़ने की आवश्यकता होगी।


zshमेरे शेल के रूप में उपयोग किए जाने वाले मुख्य कारणों में से एक यह है कि यह फ्लोटिंग पॉइंट गणित का समर्थन करता है। इस सवाल का हल एकदम सीधा है zsh:

printf %.2f $((float/1.18))

(मुझे लगता है कि किसी ने इस उत्तर के लिए एक टिप्पणी जोड़ दी है, जिसमें ट्रिम के साथ अंकगणित को सक्षम करने के लिए इस उत्तर को जोड़ा जा सकता है bash, लेकिन मुझे पूरा यकीन है कि ऐसी सुविधा अभी तक मौजूद नहीं है।)


1

यदि आपके पास परिणाम है, तो उदाहरण के लिए 2.3747888 पर विचार करें

तुमको बस यह करना है:

d=$(echo "(2.3747888+0.5)/1" | bc); echo $d

यह संख्या को सही ढंग से उदाहरण देता है:

(2.49999 + 0.5)/1 = 2.99999 

दशमलव को हटा दिया जाता है bcऔर इसलिए यह 2 के नीचे चक्कर लगाता है जैसा कि होना चाहिए


1

मुझे ऑडियो फ़ाइलों के संग्रह की कुल अवधि की गणना करनी थी।

इसलिए मुझे यह करना पड़ा:

प्रत्येक फ़ाइल के लिए अवधि प्राप्त करें ( नहीं दिखाया गया है )

B. सभी अवधि जोड़ें (वे प्रत्येक NNN.NNNNNN(fp) सेकंड में थे)

C. अलग-अलग घंटे, मिनट, सेकंड, उप-सेकंड।

D. एचआर का एक स्ट्रिंग आउटपुट: MIN: SEC: फ्रेम, जहां फ्रेम = 1/75 सेकंड।

(फ्रेम स्टूडियो में इस्तेमाल किए गए एसएमपीटीई कोड से आते हैं।)


एक: उपयोग ffprobeऔर पार्स अवधि लाइन में एक एफपी नंबर (दिखाया नहीं)

बी:

 # 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 

सी:

# 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 #

डी:

#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"

1

यहां आपकी स्क्रिप्ट का संक्षिप्त रूप दिया गया है, जो आप चाहते हैं कि आउटपुट प्रदान करने के लिए तय किया गया है:

#!/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

1

अनुरोध के अनुसार शुद्ध बीसी कार्यान्वयन

define ceil(x) { auto os,xx;x=-x;os=scale;scale=0 xx=x/1;if(xx>x).=xx-- scale=os;return(-xx) }

अगर आप फंक्शन्स .bc नामक फाइल में रखते हैं तो आप राउंड अप कर सकते हैं

echo 'ceil(3.1415)' | bc functions.bc

Http://phodd.net/gnu-bc/code/funcs.bc पर पाए गए बीसी कार्यान्वयन के लिए कोड


0
bc() {
        while :
        do
                while IFS='$\n' read i
                do
                        /usr/bin/bc <<< "scale=2; $i" | sed 's/^\./0&/'
                done
        done
}

0

आप awk का उपयोग कर सकते हैं, कोई आवश्यक पाइप नहीं:

$> PRICE=48.86
$> awk -vprice=$PRICE "BEGIN{printf(\"%.2f\n\",price/1.18+0.005)}"
41.41

पर्यावरण चर के साथ पहले से कीमत निर्धारित करें PRICE=<val>

  • फिर awk को कॉल करें - $PRICEएक awk variable के रूप में awk में जाएगा price

  • इसे तब + 100 के साथ निकटतम 100 वें तक गोल किया जाता है।

  • 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.