শেল স্ক্রিপ্টে ভাসমান পয়েন্ট সংখ্যাটির সাথে কীভাবে তুলনা করা যায়


22

আমি একটি শেল স্ক্রিপ্টে দুটি ভাসমান পয়েন্ট সংখ্যা তুলনা করতে চাই। নিম্নলিখিত কোডটি কাজ করছে না:

#!/bin/bash   
min=12.45
val=10.35    
if (( $val < $min )) ; then    
  min=$val
fi
echo $min 

উত্তর:


5

আপনি আলাদাভাবে পূর্ণসংখ্যা এবং ভগ্নাংশ অংশগুলি পরীক্ষা করতে পারেন:

#!/bin/bash
min=12.45
val=12.35    
if (( ${val%%.*} < ${min%%.*} || ( ${val%%.*} == ${min%%.*} && ${val##*.} < ${min##*.} ) )) ; then    
    min=$val
fi
echo $min

ফেড মন্তব্যগুলিতে যেমন বলেছেন, এটি কেবল তখনই কাজ করে যদি উভয় সংখ্যার ভগ্নাংশের অংশ থাকে এবং উভয় ভগ্নাংশের অংশে একই সংখ্যা থাকে। এখানে একটি সংস্করণ যা পূর্ণসংখ্যা বা ভগ্নাংশ এবং যে কোনও ব্যাশ অপারেটরের জন্য কাজ করে:

#!/bin/bash
shopt -s extglob
fcomp() {
    local oldIFS="$IFS" op=$2 x y digitx digity
    IFS='.' x=( ${1##+([0]|[-]|[+])}) y=( ${3##+([0]|[-]|[+])}) IFS="$oldIFS"
    while [[ "${x[1]}${y[1]}" =~ [^0] ]]; do
        digitx=${x[1]:0:1} digity=${y[1]:0:1}
        (( x[0] = x[0] * 10 + ${digitx:-0} , y[0] = y[0] * 10 + ${digity:-0} ))
        x[1]=${x[1]:1} y[1]=${y[1]:1} 
    done
    [[ ${1:0:1} == '-' ]] && (( x[0] *= -1 ))
    [[ ${3:0:1} == '-' ]] && (( y[0] *= -1 ))
    (( ${x:-0} $op ${y:-0} ))
}

for op in '==' '!=' '>' '<' '<=' '>='; do
    fcomp $1 $op $2 && echo "$1 $op $2"
done

4
এটি অনেক কাজ ছাড়াই স্থির করা যায় না (তুলনা করার চেষ্টা করুন 0.5এবং 0.06)। দশমিক স্বরলিপিটি ইতিমধ্যে বোঝে এমন একটি সরঞ্জাম আপনি আরও ভাল ব্যবহার করতে চাইবেন।
গিলস 'তাই মন্দ হওয়া বন্ধ করুন'

ধন্যবাদ গিলস, এটি আগের সংস্করণটির চেয়ে বেশি সাধারণভাবে কাজ করার জন্য আপডেট করেছে।
আতা

মনে রাখবেন যে এটি বলছে যে এর 1.00000000000000000000000001চেয়ে বড় 2
স্টাফেন চেজেলাস

স্টাফেন ঠিক বলেছেন। বাশের সংখ্যা উপস্থাপনের ক্ষেত্রে বিট সীমাবদ্ধতার কারণে এটি। অবশ্যই, আপনি যদি আরও কষ্ট পেতে চান তবে আপনি নিজের প্রতিনিধিত্ব ব্যবহার করতে পারেন .... :)
এটা

35

বাশ ভাসমান পয়েন্ট গণিত বুঝতে পারে না। এটি দশমিক বিন্দু যুক্ত সংখ্যাকে স্ট্রিং হিসাবে বিবেচনা করে।

পরিবর্তে awk বা বিসি ব্যবহার করুন।

#!/bin/bash

min=12.45
val=10.35

if [ 1 -eq "$(echo "${val} < ${min}" | bc)" ]
then  
    min=${val}
fi

echo "$min"

যদি আপনি প্রচুর গণিত ক্রিয়াকলাপ করার পরিকল্পনা করেন তবে অজগর বা পার্লের উপর নির্ভর করা ভাল।


12

আপনি সাধারণ ম্যানিপুলেশনের জন্য প্যাকেজ নাম্বার ব্যবহার করতে পারেন ...

আরও গুরুতর গণিতের জন্য, এই লিঙ্কটি দেখুন ... এটি বেশ কয়েকটি বিকল্পের বর্ণনা দেয়, যেমন।

  • আর / রুপলিপি (জিএনইউ আর পরিসংখ্যান গণনা এবং গ্রাফিক্স সিস্টেম)
  • অষ্টক (বেশিরভাগ মতলব সামঞ্জস্যপূর্ণ)
  • বিসি (জিএনইউ বিসি স্বেচ্ছাচারিত নির্ভুলতা ক্যালকুলেটর ভাষা)

একটি উদাহরণ numprocess

echo "123.456" | numprocess /+33.267,%2.33777/
# 67.0395291239087  

A programs for dealing with numbers from the command line

The 'num-utils' are a set of programs for dealing with numbers from the
Unix command line. Much like the other Unix command line utilities like
grep, awk, sort, cut, etc. these utilities work on data from both
standard in and data from files.

Includes these programs:
 * numaverage: A program for calculating the average of numbers.
 * numbound: Finds the boundary numbers (min and max) of input.
 * numinterval: Shows the numeric intervals between each number in a sequence.
 * numnormalize: Normalizes a set of numbers between 0 and 1 by default.
 * numgrep: Like normal grep, but for sets of numbers.
 * numprocess: Do mathematical operations on numbers.
 * numsum: Add up all the numbers.
 * numrandom: Generate a random number from a given expression.
 * numrange: Generate a set of numbers in a range expression.
 * numround: Round each number according to its value.

এখানে একটি bashহ্যাক ... এটি একটি স্ট্রিং বাম থেকে ডান তুলনা অর্থবহ করতে পূর্ণসংখ্যায় 0 টি যুক্ত করে। কোডের এই বিশেষ টুকরা প্রয়োজন যে উভয় মিনিট এবং Val আসলে একটি দশমিক বিন্দু এবং অন্তত একটি দশমিক অঙ্ক আছে।

min=12.45
val=10.35

MIN=0; VAL=1 # named array indexes, for clarity
IFS=.; tmp=($min $val); unset IFS 
tmp=($(printf -- "%09d.%s\n" ${tmp[@]}))
[[ ${tmp[VAL]} < ${tmp[MIN]} ]] && min=$val
echo min=$min

আউটপুট:

min=10.35

10

ভাসমান পয়েন্ট সংখ্যাগুলিতে সাধারণ গণনার জন্য (+ - * / এবং তুলনা), আপনি awk ব্যবহার করতে পারেন।

min=$(echo 12.45 10.35 | awk '{if ($1 < $2) print $1; else print $2}')

অথবা, আপনার কাছে যদি ksh93 বা zsh (বাশ নয়) থাকে তবে আপনি নিজের শেলের বিল্ট-ইন গাণিতিক ব্যবহার করতে পারেন, যা ভাসমান পয়েন্ট সংখ্যা সমর্থন করে supports

if ((min>val)); then ((val=min)); fi

আরো উন্নত ফ্লোটিং পয়েন্ট গণনার জন্য, সন্ধান বিসি । এটি আসলে স্বেচ্ছাচারিতা-যথার্থ ফিক্সপয়েন্ট সংখ্যার উপর কাজ করে।

সংখ্যার সারণীতে কাজ করতে, আর দেখুন ( উদাহরণ )।


6

সংখ্যা বাছাই করুন

কমান্ডটিতে sortএকটি বিকল্প রয়েছে -g( --general-numeric-sort) যা তুলনায় <"কম" বা " তুলনায় ব্যবহার করা যেতে পারে> সর্বনিম্ন বা সর্বাধিক সন্ধান করে "এর চেয়ে "এর চেয়ে বড় ।

এই উদাহরণগুলি সর্বনিম্ন সন্ধান করছে:

$ printf '12.45\n10.35\n' | sort -g | head -1
10.35

ই-নোটেশন সমর্থন করে

এটি ই-নোটেশনের মতো ভাসমান পয়েন্ট সংখ্যাগুলির সাধারণ সাধারণ স্বরলিপি সহ কাজ করে

$ printf '12.45E-10\n10.35\n' | sort -g | head -1
12.45E-10

নোট করুন E-10, প্রথম সংখ্যা তৈরি করে 0.000000001245, সত্যিই কম 10.35

অনন্তের সাথে তুলনা করতে পারে

আইইইই 7575৫ , ভাসমান বিন্দুটির মানটি কয়েকটি বিশেষ মান নির্ধারণ করে। এই তুলনাগুলির জন্য, আকর্ষণীয় বিষয়গুলি INFঅসীমের জন্য। নেতিবাচক অনন্ত আছে; উভয়ই স্ট্যান্ডার্ডে ভাল সংজ্ঞাযুক্ত মান are

$ printf 'INF\n10.35\n' | sort -g | head -1
10.35
$ printf '-INF\n10.35\n' | sort -g | head -1
-INF

sort -grপরিবর্তে সর্বাধিক ব্যবহার সন্ধান করতে sort -g, সাজানোর ক্রমটিকে বিপরীত করে:

$ printf '12.45\n10.35\n' | sort -gr | head -1
12.45

তুলনা অপারেশন

<("এর চেয়ে কম") তুলনাটি বাস্তবায়নের জন্য , যাতে এটি ifইত্যাদিতে ব্যবহার করা যায় , সর্বনিম্ন একটি মানের সাথে তুলনা করুন। যদি সর্বনিম্ন পাঠ্যের তুলনায় মানের সমান হয় তবে এটি অন্য মানের থেকে কম হয়:

$ a=12.45; b=10.35                                    
$ [ "$a" = "$(printf "$a\n$b\n" | sort -g | head -1)" ]
$ echo $?
1
$ a=12.45; b=100.35                                    
$ [ "$a" = "$(printf "$a\n$b\n" | sort -g | head -1)" ]
$ echo $?                                              
0

ভালো পরামর্শ! আমি সত্যিই আপনার অন্তর্দৃষ্টি পছন্দ করি যে চেক করা a == min(a, b)একই a <= b। এটি লক্ষণীয় যে এটি এর চেয়ে কম কঠোরভাবে পরীক্ষা করে না। আপনি যদি এটি করতে চান তবে আপনার a == min(a, b) && a != max(a, b)অন্য পাসওয়ার্ডগুলিতে পরীক্ষা করতে হবেa <= b and not a >= b
ডেভ

3

কেবল ব্যবহার করুন ksh( ksh93অবিকল) বা zsh, যা উভয়ই স্থানীয়ভাবে ভাসমান পয়েন্ট গণিত সমর্থন করে:

$ cat test.ksh
#!/bin/ksh 
min=12.45
val=10.35    
if (( $val < $min )) ; then    
  min=$val
fi
echo "$min"
$ ./test.ksh
10.35

সম্পাদনা: দুঃখিত, আমি মিস করেছি ksh93ইতিমধ্যে প্রস্তাবিত ছিল। খোলার প্রশ্নে পোস্ট করা স্ক্রিপ্টটি পরিষ্কার করার জন্য আমার উত্তরটি রাখা শেল স্যুইচের বাইরে কোনও পরিবর্তন ছাড়াই ব্যবহার করা যেতে পারে।

সম্পাদনা 2: নোট যাতে ksh93পরিবর্তনশীল সামগ্রী আপনার লোকেলের সাথে সামঞ্জস্য করা প্রয়োজন, অর্থাত একটি ফরাসি লোকালের সাথে ডটের পরিবর্তে একটি কমা ব্যবহার করা উচিত:

...
min=12,45
val=10,35
...

আরও শক্তিশালী সমাধান হ'ল স্ক্রিপ্টের শুরুতে লোকাল সেট করা নিশ্চিত করা যে এটি ব্যবহারকারীর লোকাল নির্বিশেষে এটি কাজ করবে:

...
export LC_ALL=C
min=12.45
val=10.35
...

লক্ষ্য করুন যে উপরের ksh93 স্ক্রিপ্টটি কেবলমাত্র দশমিক বিভাজক যেখানে লোকেলগুলিতে কাজ করে .(তাই দশমিক বিভাজক যেখানে অর্ধ বিশ্বে নয় ,)। zshযে সমস্যা নেই।
স্টাফেন চেজেলাস

প্রকৃতপক্ষে, উত্তরটি সম্পাদিত উত্তরটি এই পয়েন্টটি পরিষ্কার করতে।
jlliagre

LC_NUMERIC সেট করা যদি ব্যবহারকারী সেট করে থাকে তবে কাজ করবে না LC_ALL, এর অর্থ হ'ল সংখ্যাটি ব্যবহারকারীর পছন্দের বিন্যাসে প্রদর্শিত হবে না (বা ইনপুট)। সম্ভাব্যতর উন্নত পদ্ধতির জন্য unix.stackexchange.com/questions/87745/ কি-does-lc-all-c-do/… দেখুন ।
স্টাফেন চেজেলাস

@ স্টাফেনচাজেলাস এলসি_নুমারিক সমস্যা সমাধান করেছে। ওপি স্ক্রিপ্ট সিনট্যাক্স দেওয়া, আমি ধরে নিচ্ছি যে তার পছন্দসই বিভাজক .যাই হোক না কেন।
jlliagre

হ্যাঁ, তবে এটি স্ক্রিপ্ট ব্যবহারকারীর লোকেল, গুরুত্বপূর্ণ স্ক্রিপ্ট লেখকের লোকেল নয়। স্ক্রিপ্ট লেখক হিসাবে আপনার স্থানীয়করণ এবং এর পার্শ্ব প্রতিক্রিয়াগুলি অ্যাকাউন্টে নেওয়া উচিত।
স্টাফেন চেজেলাস

1
min=$(echo "${min}sa ${val}d la <a p" | dc)

ব্যবহার করে dcকরতে ক্যালকুলেটর sজন্য মান অর্ধবৃত্তাকার পার্শ্বচিত্রের মূর্তি $minরেজিস্টারে aএবং dমান uplicates $valতার প্রধান সঞ্চালনের স্ট্যাকের উপরে সম্মুখের। এরপরে এটি স্ট্যাকের শীর্ষে lথাকা সামগ্রীগুলিকে নষ্ট করে aদেয়, যে বিন্দুতে এটির মতো দেখাচ্ছে:

${min} ${val} ${val}

<স্ট্যাকের বন্ধ দুটোতে এন্ট্রি পপ এবং তাদের তুলনা করা হয়। সুতরাং স্ট্যাকটি তখন দেখতে দেখতে:

${val}

উপরের এন্ট্রিটি যদি শীর্ষের থেকে দ্বিতীয়ের চেয়ে কম থাকে তবে বিষয়বস্তুগুলি aউপরের দিকে ঠেলা দেয় , তাই স্ট্যাকটি দেখতে দেখতে:

${min} ${val}

অন্যথায় এটি কিছুই করে না এবং স্ট্যাকটি এখনও দেখতে দেখতে:

${val} 

তারপরে এটি কেবল pশীর্ষ স্ট্যাক এন্ট্রিটি মুদ্রণ করে।

সুতরাং আপনার সমস্যার জন্য:

min=12.45
val=12.35
echo "${min}sa ${val}d la <a p" | dc

###OUTPUT

12.35

কিন্তু:

min=12.45
val=12.55
echo "${min}sa ${val}d la <a p" | dc

###OUTPUT

12.45

0

কেন পুরানো, ভাল ব্যবহার করবেন না expr?

বাক্য গঠন উদাহরণ:

if expr 1.09 '>' 1.1 1>/dev/null; then
    echo 'not greater'
fi

জন্য সত্য এক্সপ্রেশন, expr প্রস্থান কোড 0, স্ট্রিং '1' stdout- এ পাঠানো হয়। মিথ্যা এক্সপ্রেশন জন্য বিপরীত ।

আমি এটি জিএনইউ এবং ফ্রিবিএসডি 8 এক্সপ্রেসের সাথে চেক করেছি।


জিএনইউ এক্সপ্রেস শুধুমাত্র পূর্ণসংখ্যার গাণিতিক তুলনা সমর্থন করে। আপনার উদাহরণ লেকোগ্রাফিকাল তুলনা ব্যবহার করে যা নেতিবাচক সংখ্যায় ব্যর্থ হবে। উদাহরণস্বরূপ, (সাফল্য) expr 1.09 '<' -1.1মুদ্রণ 1এবং প্রস্থান করবে 0
অ্যাড্রিয়ান গন্টার 21

0

দুটি (সম্ভবত ভগ্নাংশ) সংখ্যা ক্রমযুক্ত কিনা তা পরীক্ষা করার sortজন্য (যুক্তিসঙ্গত) বহনযোগ্য:

min=12.45
val=12.55
if { echo $min ; echo $val ; } | sort -n -c 2>/dev/null
then
  echo min is smallest
else
  echo val is smallest
fi

তবে, আপনি যদি সর্বনিম্ন মানটি আপডেট রাখতে চান তবে আপনার প্রয়োজন হবে না if। নম্বরগুলি বাছাই করুন এবং সর্বদা প্রথম (কমপক্ষে) একটি ব্যবহার করুন:

min=12.45
val=12.55
smallest=$({ echo $min ; echo $val ; } | sort -n | head -n 1)
echo $smallest
min=$smallest

0

সাধারণত আমি এমবেডেড পাইথন কোড সহ একই জিনিস করি:

#!/bin/sh

min=12.45
val=10.35

python - $min $val<<EOF
if ($min > $val):
        print $min
else: 
        print $val
EOF

-1
$ min=12.45
$ val=10.35
$ [ "$min" \< "$val" ] && echo $val || echo $min
$ 12.45
$ val=13
$ [ "$min" \< "$val" ] && echo $val || echo $min
$ 13

3
আপনি কি দয়া করে আপনার উত্তরে মন্তব্য করতে পারেন এবং কিছু ব্যাখ্যা যুক্ত করতে পারেন
রোমিও নিনভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.