0.02 ইনক্রিমেন্ট সহ বাশ লুপ


11

আমি যতটা ইনক্রিমেন্ট পেয়েছি সে হিসাবে আমি 0.02 এর সাথে ব্যাশে লুপ তৈরি করতে চাই

for ((i=4.00;i<5.42;i+=0.02))
do
commands
done

কিন্তু এটি কার্যকর হয়নি।


9
বাশ ভাসমান পয়েন্ট গণিত করে না।
জর্ডানম

1
ইনক্রিমেন্ট দ্বারা তৈরি করা যেতে পারে bc, তবে 4.52 এ থামানো কঠিন হতে পারে। @roaima পরামর্শ ব্যবহার করুন, 2 পদক্ষেপ সহ সহায়ক var আছে এবং ব্যবহার করুনi=$(echo $tmp_var / 100 | bc)
আরচেমার


5
আপনি সাধারণত লুপ সূচক হিসাবে ভাসমান ব্যবহার করতে চান না । আপনি প্রতিটি পুনরাবৃত্তিতে ত্রুটি জমা করছেন।
ইসানায়ে

উত্তর:


18

পড়া bash man পৃষ্ঠা নিম্নলিখিত তথ্য দেয়:

for (( expr1 ; expr2 ; expr3 )) ; do list ; done

প্রথমে পাটিগণিতের expr1প্রকাশটি নীচে বর্ণিত মূল্যায়ন মূল্যায়নের অধীনে বর্ণিত বিধি অনুসারে মূল্যায়ন করা হয়। [...]

এবং তারপরে আমরা এই বিভাগটি পাই

শিল্প মূল্যায়ন

শেলটি কয়েকটি পরিস্থিতিতে গাণিতিক এক্সপ্রেশনগুলি মূল্যায়নের অনুমতি দেয় ( letdeclareবিল্টিন কমান্ড এবং গাণিতিক সম্প্রসারণ দেখুন)। অতিরিক্ত প্রবাহের জন্য কোনও পরীক্ষা ছাড়াই স্থির-প্রস্থের পূর্ণসংখ্যায় মূল্যায়ন করা হয় [...]

সুতরাং এটি স্পষ্ট দেখা যায় যে আপনি একটি ব্যবহার করতে পারবেন না forঅ পূর্ণসংখ্যা মান লুপ।

একটি সমাধান হ'ল আপনার সমস্ত লুপ উপাদানগুলি 100 দ্বারা গুণিত করা হতে পারে, আপনি যেখানে পরে সেগুলি ব্যবহার করেন এটির জন্য এটির অনুমতি দিয়ে:

for ((k=400;k<542;k+=2))
do
    i=$(bc <<<"scale=2; $k / 100" )    # when k=402 you get i=4.02, etc.
    ...
done

আমি মনে করি k=400;k<542;k+=2এটি সম্ভাব্য ভাসমান পয়েন্ট পাটিগণিত ঝামেলা এড়ানোর সাথে এটিই সেরা সমাধান ।
হিউজেনস

1
নোট করুন যে লুপের প্রতিটি পুনরাবৃত্তির জন্য, আপনি একটি পাইপ তৈরি করেন (এর আউটপুট পড়তে bc), একটি প্রক্রিয়া কাঁটাচামচ করেন, একটি অস্থায়ী ফাইল তৈরি করুন (এখানে-স্ট্রিংয়ের জন্য) এতে এক্সিকিউট করুন bc(যা বোঝায় একটি এক্সিকিউটেবল এবং শেয়ার্ড লাইব্রেরি লোড করা এবং তাদের সূচনা করে), এটির জন্য অপেক্ষা করুন এবং সাফ করুন। bcলুপটি করতে একবার চালানো অনেক বেশি দক্ষ হবে।
স্টাফেন চেজেলাস

@ স্টাফেনচাজেলাস হ্যাঁ, একমত হয়েছেন। তবে যদি এটি বাধা হয় তবে আমরা সম্ভবত ভুল ভাষায় কোডটি লিখছি। ওওআই যা কম অদক্ষ (!)? i=$(bc <<< "scale...")বাi=$(echo "scale..." | bc)
রোয়াইমা

1
আমার দ্রুত পরীক্ষা থেকে, নল সংস্করণ zsh দ্রুত (কোথায় <<<থেকে আসে), bashএবং ksh। মনে রাখবেন যে অন্য শেলটিতে স্যুইচ করা bashআপনাকে অন্য সিনট্যাক্স ব্যবহারের চেয়ে আরও ভাল পারফরম্যান্স বাড়িয়ে তুলবে।
স্টাফেন চেজেলাস

(এবং শাঁস অধিকাংশ সমর্থন করে <<<(zsh, mksh, ksh93, যশ) ও ফ্লোটিং পয়েন্ট arithmetics (সমর্থন zsh, ksh93, yash))।
স্টাফেন চেজেলাস

18

শাঁসগুলিতে লুপগুলি এড়িয়ে চলুন।

আপনি যদি গাণিতিক করতে চান তবে ব্যবহার করুন awkবা bc:

awk '
  BEGIN{
    for (i = 4.00; i < 5.42; i+ = 0.02)
      print i
  }'

অথবা

bc << EOF
for (i = 4.00; i < 5.42; i += 0.02)  i
EOF

নোট করুন awk(বিপরীতে bc) আপনার প্রসেসরের সাথে doubleভাসমান পয়েন্ট নম্বর উপস্থাপনা (সম্ভবত আইইইই 754 প্রকার) এর সাথে কাজ করে। ফলস্বরূপ, যেহেতু এই সংখ্যাগুলি those দশমিক সংখ্যার দ্বিপাক্ষিক অনুমান, তাই আপনার কিছু চমক থাকতে পারে:

$ gawk 'BEGIN{for (i=0; i<=0.3; i+=0.1) print i}'
0
0.1
0.2

আপনি যদি একটি যুক্ত করেন OFMT="%.17g"তবে নিখোঁজ হওয়ার কারণটি দেখতে পারেন 0.3:

$ gawk 'BEGIN{OFMT="%.17g"; for (i=0; i<=0.5; i+=0.1) print i}'
0
0.10000000000000001
0.20000000000000001
0.30000000000000004
0.40000000000000002
0.5

bc স্বেচ্ছাচারিত নির্ভুলতা না তাই এই ধরণের সমস্যা নেই।

নোট করুন যে ডিফল্টরূপে (যদি না আপনি আউটপুট ফর্ম্যাটটি পরিবর্তন করে OFMTবা printfস্পষ্ট বিন্যাসের নির্দিষ্টকরণের সাথে ব্যবহার না করেন), ভাসমান পয়েন্ট সংখ্যা প্রদর্শনের জন্য awkব্যবহার করে %.6g, তাই 1000,000 এর উপরে ভাসমান পয়েন্ট সংখ্যাগুলির জন্য 1e6 এবং তারপরে স্যুইচ হবে এবং উচ্চ সংখ্যার জন্য ভগ্নাংশটি কেটে যাবে (100000.02 100000 হিসাবে প্রদর্শিত হবে)।

যদি আপনার সত্যিই শেল লুপটি ব্যবহার করতে হয়, কারণ উদাহরণস্বরূপ আপনি সেই লুপটির প্রতিটি পুনরাবৃত্তির জন্য নির্দিষ্ট কমান্ডগুলি চালাতে চান, হয় হয় ভাসমান পয়েন্টের পাটিগণিত সমর্থন সহ একটি শেল ব্যবহার করুন zsh, yashবা ksh93উপরের মত একটি কমান্ডের সাথে মানগুলির তালিকা তৈরি করা উচিত (বা seqউপলভ্য হলে) এবং এর আউটপুট লুপ করুন।

ভালো লেগেছে:

unset -v IFS # configure split+glob for default word splitting
for i in $(seq 4 0.02 5.42); do
  something with "$i"
done

বা:

seq 4 0.02 5.42 | while IFS= read i; do
  something with "$i"
done

আপনি যদি আপনার প্রসেসরের ভাসমান পয়েন্ট সংখ্যাগুলির সীমাটি না চাপেন তবে উপরের সংস্করণটির seqচেয়ে ভাসমান পয়েন্টের আনুষঙ্গিকতায় আরও ত্রুটিপূর্ণভাবে পরিচালনা awkকরবে grace

আপনার যদি seq(একটি জিএনইউ কমান্ড) না থাকে তবে আপনি একটি কার্যকারিতা হিসাবে আরও নির্ভরযোগ্য একটি করতে পারেন:

seq() { # args: first increment last
  bc << EOF
    for (i = $1; i <= $3; i += $2) i
EOF
}

এটি ভালো কাজের জন্য আরও ভাল কাজ করবে seq 100000000001 0.000000001 100000000001.000000005। তবে মনে রাখবেন যে নির্বিচারে উচ্চ নির্ভুলতার সাথে সংখ্যা থাকা খুব বেশি কার্যকর হবে না যদি আমরা তাদেরকে যে কমান্ডগুলিতে সমর্থন করি না তাদের কাছে প্রেরণ করতে চলেছি।


আমি awk ব্যবহারের প্রশংসা করি! +1
প্যান্ড্যা

unset IFSপ্রথম উদাহরণে আপনার প্রয়োজন কেন ?
ব্যবহারকারী 1717828

@ ব্যবহারকারী 1717828, আদর্শভাবে, সেই বিভাজন + গ্লোব অনুরোধের সাথে আমরা নিউলাইন চরিত্রগুলিতে বিভক্ত করতে চাই। আমরা এটি দিয়ে করতে পারি IFS=$'\n'তবে এটি সমস্ত শেলের মধ্যে কাজ করে না। বা IFS='<a-litteral-newline-here>'কিন্তু এটি খুব সুগঠিত নয়। অথবা আমরা পরিবর্তে শব্দের (স্পেস, ট্যাব, নিউলাইন) বিভাজন করতে পারি যেমন আপনি $ আইএফএসের ডিফল্ট মান সহ পেয়ে থাকেন বা যদি আপনি আইএফএস আনসেট করেন এবং এখানেও কাজ করেন।
স্টাফেন চেজেলাস

@ ব্যবহারকারী 1717828: আমাদের জগাখিচির দরকার নেই IFS, কারণ আমরা জানি যে seqএর আউটপুটে ফাঁকা স্থান নেই যা আমাদের বিভাজন এড়াতে হবে। এটি বেশিরভাগ ক্ষেত্রে নিশ্চিত হয়ে থাকে যে আপনি উপলব্ধি করেছেন যে এই উদাহরণটি নির্ভর করে IFS, যা কোনও ভিন্ন তালিকা তৈরির কমান্ডের জন্য গুরুত্বপূর্ণ।
পিটার কর্ডেস

1
@ পিটারকর্ডস, এটি রয়েছে তাই আইএফএসের আগে যা সেট করা হয়েছিল সে সম্পর্কে আমাদের কোনও অনুমান করার দরকার নেই।
স্টাফেন চেজেলাস


0

অন্যরা যেমন পরামর্শ দিয়েছে, আপনি বিসি ব্যবহার করতে পারেন:

i="4.00"

while [[ "$(bc <<< "$i < 5.42")" == "1" ]]; do
    # do something with i
    i="$(bc <<< "$i + 0.02")"
done
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.