টি এল; ডিআর
কেবল sigf
বিভাগে ফাংশনটি অনুলিপি করুন এবং ব্যবহার করুন A reasonably good "significant numbers" function:
। ড্যাশ সহ কাজ করার জন্য এটি লিখিত (এই উত্তরের সমস্ত কোড হিসাবে) ।
এটা তোলে দেব printf
করার পড়তা এন এর পূর্ণসংখ্যা অংশ দিয়ে $sig
ডিজিটের।
দশমিক বিভাজক সম্পর্কে।
প্রিন্টফের সাহায্যে সমাধানের প্রথম সমস্যাটি হ'ল "দশমিক চিহ্ন" এর প্রভাব এবং ব্যবহার যা মার্কিন যুক্তরাষ্ট্রে একটি পয়েন্ট এবং ডিই-তে একটি কমা (উদাহরণস্বরূপ)। এটি একটি সমস্যা কারণ কিছু লোকেলের (বা শেল) জন্য যা কাজ করে তা অন্য কোনও লোকেলের সাথে ব্যর্থ হবে। উদাহরণ:
$ dash -c 'printf "%2.3f\n" 12.3045'
12.305
$ ksh -c 'printf "%2.3f\n" 12.3045'
ksh: printf: 12.3045: arithmetic syntax error
ksh: printf: 12.3045: arithmetic syntax error
ksh: printf: warning: invalid argument of type f
12,000
$ ksh -c 'printf "%2.2f\n" 12,3045'
12,304
একটি সাধারণ (এবং ভুল সমাধান) হ'ল LC_ALL=C
প্রিন্টফ কমান্ডের জন্য সেট করা । তবে এটি দশমিক চিহ্নটিকে একটি নির্দিষ্ট দশমিক পয়েন্টে সেট করে। লোকালগুলির জন্য যেখানে কমা (বা অন্যান্য) সাধারণ ব্যবহৃত চরিত্র যা একটি সমস্যা that
সমাধানটি হ'ল লোকেল দশমিক বিভাজকটি কী তা চালনা করে তা চালানোর জন্য স্ক্রিপ্টের ভিতরে খুঁজে বের করা। এটি বেশ সহজ:
$ printf '%1.1f' 0
0,0 # for a comma locale (or shell).
শূন্যগুলি সরানো হচ্ছে:
$ dec="$(IFS=0; printf '%s' $(printf '%.1f'))"; echo "$dec"
, # for a comma locale (or shell).
সেই মানটি পরীক্ষার তালিকার সাথে ফাইলটি পরিবর্তন করতে ব্যবহৃত হয়:
sed -i 's/[,.]/'"$dec"'/g' infile
এটি কোনও শেল বা লোকালে রানগুলি স্বয়ংক্রিয়ভাবে বৈধ করে তোলে।
কিছু বেসিক।
বিন্যাসে %.*e
বা এমনকি প্রিন্টফের সাথে ফর্ম্যাট করতে নম্বরটি কাটা স্বজ্ঞাত হওয়া উচিত %.*g
। ব্যবহারের মধ্যে প্রধান পার্থক্য %.*e
বা %.*g
কীভাবে তারা অঙ্কগুলি গণনা করে। একটিতে পূর্ণ গণনা ব্যবহার করা হয়, অন্যটির গণনা কম 1:
$ printf '%.*e %.*g' $((4-1)) 1,23456e0 4 1,23456e0
1,235e+00 1,235
এটি 4 টি গুরুত্বপূর্ণ অঙ্কের জন্য ভাল কাজ করেছে।
সংখ্যাটি সংখ্যা থেকে কাটা যাওয়ার পরে, 0 থেকে আলাদা (যেমন এটি উপরে ছিল) আলাদা করে সংখ্যার ফর্ম্যাট করতে আমাদের একটি অতিরিক্ত পদক্ষেপের প্রয়োজন।
$ N=$(printf '%.*e' $((4-1)) 1,23456e3); echo "$N"
1,235e+03
$ printf '%4.0f' "$N"
1235
এটি সঠিকভাবে কাজ করে। পূর্ণসংখ্যার অংশের গণনা (দশমিক চিহ্নের বাম দিকে) ব্যয়কারীর মান ($ এক্সপ্রেস) is দশমিক সংখ্যার গণনা হ'ল দশমিক বিভাজকের বাম অংশে ইতিমধ্যে ব্যবহৃত অঙ্কের পরিমাণের পরিমাণ ($ সিগ) কম:
a=$((exp<0?0:exp)) ### count of integer characters.
b=$((exp<sig?sig-exp:0)) ### count of decimal characters.
printf '%*.*f' "$a" "$b" "$N"
যেহেতু f
বিন্যাসের অবিচ্ছেদ্য অংশটির কোনও সীমা নেই, প্রকৃতপক্ষে এটি স্পষ্টভাবে ঘোষণা করার দরকার নেই এবং এটি (সরল) কোডটি কার্যকর করে:
a=$((exp<sig?sig-exp:0)) ### count of decimal characters.
printf '%0.*f' "$a" "$N"
প্রথম বিচার।
একটি প্রথম ফাংশন যা আরও স্বয়ংক্রিয় পদ্ধতিতে এটি করতে পারে:
# Function significant (number, precision)
sig1(){
sig=$(($2>0?$2:1)) ### significant digits (>0)
N=$(printf "%0.*e" "$(($sig-1))" "$1") ### N in sci (cut to $sig digits).
exp=$(echo "${N##*[eE+]}+1"|bc) ### get the exponent.
a="$((exp<sig?sig-exp:0))" ### calc number of decimals.
printf "%0.*f" "$a" "$N" ### re-format number.
}
এই প্রথম প্রচেষ্টাটি বহু সংখ্যার সাথে কাজ করে তবে এমন সংখ্যায় ব্যর্থ হবে যার জন্য উপলভ্য অঙ্কগুলির পরিমাণ উল্লেখযোগ্য গণনার চেয়ে কম এবং ব্যয়কারী -4 এর চেয়ে কম:
Number sig Result Correct?
123456789 --> 4< 123500000 >--| yes
23455 --> 4< 23460 >--| yes
23465 --> 4< 23460 >--| yes
1,2e-5 --> 6< 0,0000120000 >--| no
1,2e-15 -->15< 0,00000000000000120000000000000 >--| no
12 --> 6< 12,0000 >--| no
এটি অনেকগুলি শূন্য যুক্ত করবে যাগুলির প্রয়োজন নেই।
দ্বিতীয় বিচার।
এটি সমাধান করার জন্য আমাদের ঘেরের N এবং পরিষ্কারের কোনও জিরো দরকার to তারপরে আমরা উপলব্ধ অঙ্কগুলির কার্যকর দৈর্ঘ্য পেতে পারি এবং এটিতে কাজ করতে পারি:
# Function significant (number, precision)
sig2(){ local sig N exp n len a
sig=$(($2>0?$2:1)) ### significant digits (>0)
N=$(printf "%+0.*e" "$(($sig-1))" "$1") ### N in sci (cut to $sig digits).
exp=$(echo "${N##*[eE+]}+1"|bc) ### get the exponent.
n=${N%%[Ee]*} ### remove sign (first character).
n=${n%"${n##*[!0]}"} ### remove all trailing zeros
len=$(( ${#n}-2 )) ### len of N (less sign and dec).
len=$((len<sig?len:sig)) ### select the minimum.
a="$((exp<len?len-exp:0))" ### use $len to count decimals.
printf "%0.*f" "$a" "$N" ### re-format the number.
}
যাইহোক, এটি ভাসমান পয়েন্ট গণিত ব্যবহার করছে, এবং "ভাসমান পয়েন্টে কিছুই সহজ নয়": আমার সংখ্যাগুলি কেন যোগ হচ্ছে না?
তবে "ভাসমান পয়েন্ট" এর কিছুই সহজ নয়।
printf "%.2g " 76500,00001 76500
7,7e+04 7,6e+04
যাহোক:
printf "%.2g " 75500,00001 75500
7,6e+04 7,6e+04
কেন ?:
printf "%.32g\n" 76500,00001e30 76500e30
7,6500000010000000001207515928855e+34
7,6499999999999999997831226199114e+34
এবং, এছাড়াও, কমান্ডটি printf
অনেকগুলি শেলের একটি অন্তর্নির্মিত। শেল দিয়ে
কী printf
মুদ্রণ পরিবর্তন হতে পারে:
$ dash -c 'printf "%.*f" 4 123456e+25'
1234560000000000020450486779904.0000
$ ksh -c 'printf "%.*f" 4 123456e+25'
1234559999999999999886313162278,3840
$ dash ./script.sh
123456789 --> 4< 123500000 >--| yes
23455 --> 4< 23460 >--| yes
23465 --> 4< 23460 >--| yes
1.2e-5 --> 6< 0.000012 >--| yes
1.2e-15 -->15< 0.0000000000000012 >--| yes
12 --> 6< 12 >--| yes
123456e+25 --> 4< 1234999999999999958410892148736 >--| no
একটি যুক্তিসঙ্গতভাবে ভাল "উল্লেখযোগ্য সংখ্যা" ফাংশন:
dec=$(IFS=0; printf '%s' $(printf '%.1f')) ### What is the decimal separator?.
sed -i 's/[,.]/'"$dec"'/g' infile
zeros(){ # create an string of $1 zeros (for $1 positive or zero).
printf '%.*d' $(( $1>0?$1:0 )) 0
}
# Function significant (number, precision)
sigf(){ local sig sci exp N sgn len z1 z2 b c
sig=$(($2>0?$2:1)) ### significant digits (>0)
N=$(printf '%+e\n' $1) ### use scientific format.
exp=$(echo "${N##*[eE+]}+1"|bc) ### find ceiling{log(N)}.
N=${N%%[eE]*} ### cut after `e` or `E`.
sgn=${N%%"${N#-}"} ### keep the sign (if any).
N=${N#[+-]} ### remove the sign
N=${N%[!0-9]*}${N#??} ### remove the $dec
N=${N#"${N%%[!0]*}"} ### remove all leading zeros
N=${N%"${N##*[!0]}"} ### remove all trailing zeros
len=$((${#N}<sig?${#N}:sig)) ### count of selected characters.
N=$(printf '%0.*s' "$len" "$N") ### use the first $len characters.
result="$N"
# add the decimal separator or lead zeros or trail zeros.
if [ "$exp" -gt 0 ] && [ "$exp" -lt "$len" ]; then
b=$(printf '%0.*s' "$exp" "$result")
c=${result#"$b"}
result="$b$dec$c"
elif [ "$exp" -le 0 ]; then
# fill front with leading zeros ($exp length).
z1="$(zeros "$((-exp))")"
result="0$dec$z1$result"
elif [ "$exp" -ge "$len" ]; then
# fill back with trailing zeros.
z2=$(zeros "$((exp-len))")
result="$result$z2"
fi
# place the sign back.
printf '%s' "$sgn$result"
}
এবং ফলাফলগুলি হ'ল:
$ dash ./script.sh
123456789 --> 4< 123400000 >--| yes
23455 --> 4< 23450 >--| yes
23465 --> 4< 23460 >--| yes
1.2e-5 --> 6< 0.000012 >--| yes
1.2e-15 -->15< 0.0000000000000012 >--| yes
12 --> 6< 12 >--| yes
123456e+25 --> 4< 1234000000000000000000000000000 >--| yes
123456e-25 --> 4< 0.00000000000000000001234 >--| yes
-12345.61234e-3 --> 4< -12.34 >--| yes
-1.234561234e-3 --> 4< -0.001234 >--| yes
76543 --> 2< 76000 >--| yes
-76543 --> 2< -76000 >--| yes
123456 --> 4< 123400 >--| yes
12345 --> 4< 12340 >--| yes
1234 --> 4< 1234 >--| yes
123.4 --> 4< 123.4 >--| yes
12.345678 --> 4< 12.34 >--| yes
1.23456789 --> 4< 1.234 >--| yes
0.1234555646 --> 4< 0.1234 >--| yes
0.0076543 --> 2< 0.0076 >--| yes
.000000123400 --> 2< 0.00000012 >--| yes
.000001234000 --> 2< 0.0000012 >--| yes
.000012340000 --> 2< 0.000012 >--| yes
.000123400000 --> 2< 0.00012 >--| yes
.001234000000 --> 2< 0.0012 >--| yes
.012340000000 --> 2< 0.012 >--| yes
.123400000000 --> 2< 0.12 >--| yes
1.234 --> 2< 1.2 >--| yes
12.340 --> 2< 12 >--| yes
123.400 --> 2< 120 >--| yes
1234.000 --> 2< 1200 >--| yes
12340.000 --> 2< 12000 >--| yes
123400.000 --> 2< 120000 >--| yes
%f
/%g
, তবে এটিprintf
তর্ক and এবংprintf
একটি পসিক্স শেল রাখার জন্য একটি পসিক্সের প্রয়োজন হয় না । আমি মনে করি সেখানে সম্পাদনার পরিবর্তে আপনার মন্তব্য করা উচিত ছিল।