আমি এটি নিশ্চিত করতে চাই যে প্রয়োজনের ক্ষেত্রে পূর্ণসংখ্যার একটি বিভাজন সর্বদা গোল করা হয়। এর চেয়ে ভাল উপায় আর কি আছে? প্রচুর ingালাই চলছে। :-)
(int)Math.Ceiling((double)myInt1 / myInt2)
আমি এটি নিশ্চিত করতে চাই যে প্রয়োজনের ক্ষেত্রে পূর্ণসংখ্যার একটি বিভাজন সর্বদা গোল করা হয়। এর চেয়ে ভাল উপায় আর কি আছে? প্রচুর ingালাই চলছে। :-)
(int)Math.Ceiling((double)myInt1 / myInt2)
উত্তর:
আপডেট: এই প্রশ্নটি জানুয়ারী 2013 এ আমার ব্লগের বিষয় ছিল । মহান প্রশ্নের জন্য ধন্যবাদ!
পূর্ণসংখ্যার গাণিতিক সঠিক হওয়া শক্ত। যেমনটি এতদূর পর্যন্ত প্রদর্শিত হয়েছে, আপনি যে কোনও "চালাক" কৌশলটি করার চেষ্টা করবেন, প্রতিক্রিয়াগুলি ভাল যে আপনি একটি ভুল করেছেন। এবং যখন কোনও ত্রুটি পাওয়া যায়, ত্রুটিটি ঠিক করার জন্য কোড পরিবর্তন করা ঠিক করে অন্য কোনও কিছু ভেঙে যায় কিনা তা বিবেচনা না করেই সমস্যা সমাধানের কোনও ভাল কৌশল নয়। এখনও অবধি আমাদের মনে হয়েছে যে এটি সম্পূর্ণরূপে নয়-বিশেষত-কঠিন সমস্যার পোস্টের জন্য পাঁচটি ভিন্ন ভুল পূর্ণসংখ্যার গাণিতিক সমাধান solutions
পূর্ণসংখ্যার গাণিতিক সমস্যাগুলির কাছে আসার সঠিক উপায় - এটি যেভাবে উত্তরটি প্রথমবারের মতো পাওয়ার সম্ভাবনা বাড়িয়ে দেয় - তা হ'ল সমস্যাটি সাবধানতার সাথে যোগাযোগ করা, একবারে এক ধাপে সমাধান করা এবং করার ক্ষেত্রে ইঞ্জিনিয়ারিংয়ের নীতিগুলি ব্যবহার করা is তাই।
আপনি যেটি প্রতিস্থাপনের চেষ্টা করছেন তার স্পেসিফিকেশন পড়ে শুরু করুন। পূর্ণসংখ্যা বিভাগের স্পেসিফিকেশন স্পষ্টভাবে বলে:
বিভাগটি শূন্যের দিকে ফলাফলকে বৃত্তাকারে করে
ফল দুটি শূন্য বা ধনাত্মক হয় যখন দুটি অপারেন্ডের একই চিহ্ন থাকে এবং শূন্য বা নেতিবাচক থাকে যখন দুটি অপারেটের বিপরীত চিহ্ন থাকে
যদি বাম অপারেন্ডটি ক্ষুদ্রতম উপস্থাপনযোগ্য int হয় এবং ডান অপরেন্ডটি opera1 হয় তবে একটি ওভারফ্লো ঘটে। [...] এটি [বাস্তবায়িত-সংজ্ঞায়িত] [একটি অ্যারিমেটিকেক্সেপশন] নিক্ষেপ করা হয়েছে বা ওভারফ্লোটি বাম অপারেণ্ডের ফলস্বরূপ মানটির সাথে মিলিত হয়নি।
যদি ডান অপরেন্ডের মান শূন্য হয় তবে একটি সিস্টেম.ডাইভাইডবাইজারো এক্সপশন নিক্ষেপ করা হবে।
আমরা যা চাই তা হ'ল একটি পূর্ণসংখ্যা বিভাগ ফাংশন যা ভাগফলকে গণনা করে তবে ফলাফলটি সর্বদা শূন্যের দিকে না দিয়ে সর্বদা উপরের দিকে ঘোরায় ।
সুতরাং যে ফাংশন জন্য একটি স্পেসিফিকেশন লিখুন। আমাদের ফাংশনটি int DivRoundUp(int dividend, int divisor)
প্রতিটি সম্ভাব্য ইনপুট জন্য আচরণ সংজ্ঞায়িত করা আবশ্যক। সেই অপরিবর্তিত আচরণটি গভীর উদ্বেগজনক, সুতরাং আসুন আমরা এটিকে নির্মূল করি। আমরা বলব যে আমাদের অপারেশনের এই স্পেসিফিকেশন রয়েছে:
বিভাজক শূন্য হলে অপারেশন নিক্ষেপ করে
লভ্যাংশ যদি আন্তঃমিনাল এবং বিভাজক -1 হয় তবে অপারেশন নিক্ষেপ করে
যদি কোনও অবশিষ্ট না থাকে - বিভাগটি 'সম' হয় - তবে ফেরতের মানটি অবিচ্ছেদ্য ভাগফল হয় quot
অন্যথায় এটি ক্ষুদ্রতম পূর্ণসংখ্যার সাথে ভাগ করে যা ভাগফলের চেয়ে বড় হয়, এটি সর্বদা গোল হয়।
এখন আমাদের একটি স্পেসিফিকেশন রয়েছে, তাই আমরা জানি যে আমরা পরীক্ষার যোগ্য নকশা নিয়ে আসতে পারি । ধরা যাক আমরা একটি অতিরিক্ত নকশার মানদণ্ড যুক্ত করেছি যে সমস্যাটি বিবৃতিতে "ডাবল" সমাধানটি স্পষ্টভাবে প্রত্যাখ্যান করা হওয়ায় সমস্যাটি কেবলমাত্র দ্বিগুণ হিসাবে গণনা না করে পূর্ণসংখ্যার গাণিতিক দ্বারা সমাধান করা হবে।
সুতরাং আমরা কি গণনা করা আবশ্যক? স্পষ্টতই, কেবলমাত্র পূর্ণসংখ্যার গাণিতিক অবস্থায় থাকা অবস্থায় আমাদের অনুমানগুলি পূরণ করতে আমাদের তিনটি তথ্য জানতে হবে facts প্রথমত, পূর্ণসংখ্যাফলটি কী ছিল? দ্বিতীয়ত, বিভাগ কি বাকী মুক্ত ছিল? এবং তৃতীয়, যদি না হয়, পূর্ণসংখ্যা ভাগটি বৃত্তাকার বা নীচে দ্বারা গুণিত হয়েছিল?
এখন যে আমাদের একটি স্পেসিফিকেশন এবং একটি নকশা আছে, আমরা কোড লেখা শুরু করতে পারি।
public static int DivRoundUp(int dividend, int divisor)
{
if (divisor == 0 ) throw ...
if (divisor == -1 && dividend == Int32.MinValue) throw ...
int roundedTowardsZeroQuotient = dividend / divisor;
bool dividedEvenly = (dividend % divisor) == 0;
if (dividedEvenly)
return roundedTowardsZeroQuotient;
// At this point we know that divisor was not zero
// (because we would have thrown) and we know that
// dividend was not zero (because there would have been no remainder)
// Therefore both are non-zero. Either they are of the same sign,
// or opposite signs. If they're of opposite sign then we rounded
// UP towards zero so we're done. If they're of the same sign then
// we rounded DOWN towards zero, so we need to add one.
bool wasRoundedDown = ((divisor > 0) == (dividend > 0));
if (wasRoundedDown)
return roundedTowardsZeroQuotient + 1;
else
return roundedTowardsZeroQuotient;
}
এই চালাক কি? না? সুন্দর? সংক্ষেপে? স্পেসিফিকেশন অনুযায়ী সঠিক? আমি এটি বিশ্বাস করি, তবে আমি এটি পুরোপুরি পরীক্ষা করে দেখিনি। যদিও দেখতে বেশ সুন্দর লাগছে।
আমরা এখানে পেশাদার; ভাল ইঞ্জিনিয়ারিং অনুশীলন ব্যবহার করুন। আপনার সরঞ্জামগুলি গবেষণা করুন, পছন্দসই আচরণটি নির্দিষ্ট করুন, প্রথমে ত্রুটির ঘটনাগুলি বিবেচনা করুন এবং কোডটির স্পষ্টত সঠিকতার উপর জোর দেওয়ার জন্য লিখুন। এবং আপনি যখন কোনও বাগ খুঁজে পান, তখন বিবেচনা করুন যে আপনার অ্যালগরিদমটি শুরু করার জন্য গভীরভাবে ত্রুটিযুক্ত কিনা আপনি কেবল এলোমেলোভাবে চারপাশের তুলনাগুলির দিকগুলি অদলবদল করতে শুরু করুন এবং ইতিমধ্যে কাজ করা জিনিসগুলি ভাঙ্গুন।
এখানে এখনও পর্যন্ত সমস্ত উত্তর বরং জটিল বলে মনে হচ্ছে।
সি # এবং জাভাতে ধনাত্মক লভ্যাংশ এবং বিভাজকের জন্য আপনার কেবলমাত্র এটি করা দরকার:
( dividend + divisor - 1 ) / divisor
((13-1)%3)+1)
ফলাফল হিসাবে 1 দেয়। সঠিক ধরণের বিভাগ গ্রহণ, 1+(dividend - 1)/divisor
ইতিবাচক লভ্যাংশ এবং বিভাজকের জন্য উত্তর হিসাবে একই ফলাফল দেয়। এছাড়াও, কোনও ওভারফ্লো সমস্যা নয়, তবে কৃত্রিম সেগুলি হতে পারে।
স্বাক্ষরিত পূর্ণসংখ্যার জন্য:
int div = a / b;
if (((a ^ b) >= 0) && (a % b != 0))
div++;
স্বাক্ষরবিহীন পূর্ণসংখ্যার জন্য:
int div = a / b;
if (a % b != 0)
div++;
পূর্ণসংখ্যা বিভাগ ' /
' শূন্যের (গোলের 7..7.২) দিকে গোলকে সংজ্ঞায়িত করা হয়েছে, তবে আমরা গোল করতে চাই। এর অর্থ negativeণাত্মক উত্তরগুলি ইতিমধ্যে সঠিকভাবে গোল করা হয়েছে তবে ইতিবাচক উত্তরগুলি সামঞ্জস্য করা দরকার।
অ-শূন্য ইতিবাচক উত্তরগুলি সনাক্ত করা সহজ, তবে উত্তর শূন্যটি একটি সামান্য কৌশলযুক্ত, কারণ এটি হয় নেতিবাচক মানের গোলাকার বা একটি ধনাত্মক উত্তরকে গোল করে দেওয়া হতে পারে।
সবচেয়ে নিরাপদ বেট হ'ল উভয় পূর্ণসংখ্যার চিহ্ন একইরকম কিনা তা পরীক্ষা করে উত্তরটি ইতিবাচক হওয়া উচিত কিনা তা সনাক্ত করা। ^
দুটি মানগুলিতে ইন্টিজার জোর অপারেটর ' ' এর ফলে 0 টি সাইন-বিট আসবে, যার অর্থ একটি অ-নেতিবাচক ফলাফল, সুতরাং চেকটি (a ^ b) >= 0
নির্ধারণ করে যে ফলাফলটি গোল করার আগে ইতিবাচক হওয়া উচিত ছিল। এছাড়াও লক্ষ করুন যে স্বাক্ষরবিহীন পূর্ণসংখ্যার জন্য, প্রতিটি উত্তর স্পষ্টতই ইতিবাচক, সুতরাং এই চেকটি বাদ দেওয়া যেতে পারে।
কেবলমাত্র চেকগুলি তখনই কোনও রাউন্ডিং হয়েছে কিনা, যার জন্য a % b != 0
কাজটি করবে।
পাটিগণিত (পূর্ণসংখ্যা বা অন্যথায়) এটি যতটা সহজ লাগে তেমন সহজ নয়। চিন্তাভাবনা সব সময় প্রয়োজন।
এছাড়াও, যদিও আমার চূড়ান্ত উত্তর সম্ভবত 'সাধারণ' বা 'সুস্পষ্ট' বা ভাসমান পয়েন্টের উত্তর হিসাবে সম্ভবত 'দ্রুত' নয়, এটির জন্য আমার কাছে খুব শক্তিশালী খালাসের গুণ রয়েছে; আমি এখন উত্তরের মাধ্যমে যুক্তি দিয়েছি, সুতরাং আমি আসলে নিশ্চিত যে এটি সঠিক (যতক্ষণ না কেউ স্মার্ট আমাকে অন্যথায় বলেন - এরিকের দিকের দিকে ঝাপটা দৃষ্টি -)।
ফ্লোটিং পয়েন্ট উত্তর সম্পর্কে নিশ্চিতভাবে একই অনুভূতি পেতে, আমি আরো কিনা কোন অবস্থার যার অধীনে ফ্লোটিং পয়েন্ট স্পষ্টতা ভাবে পেতে পারে চিন্তা করতে (এবং সম্ভবত আরো জটিল) থাকতে চাই, এবং কিনা Math.Ceiling
সম্ভবত আছে 'ঠিক ডান' ইনপুটগুলিতে অনাকাঙ্ক্ষিত কিছু।
প্রতিস্থাপন করুন (নোট আমি এর myInt1
সাথে দ্বিতীয়টি প্রতিস্থাপন করেছি myInt2
, ধরে নিলাম এটিই আপনি বোঝাতে চেয়েছিলেন):
(int)Math.Ceiling((double)myInt1 / myInt2)
সঙ্গে:
(myInt1 - 1 + myInt2) / myInt2
একমাত্র সতর্কতা হ'ল myInt1 - 1 + myInt2
আপনি যদি ব্যবহার করছেন পূর্ণসংখ্যার ধরণের প্রবহমান হয় তবে আপনি যা প্রত্যাশা করেছিলেন তা পেতে পারেন না।
কারণ এটি ভুল : -1000000 এবং 3999 -250 দেওয়া উচিত, এটি -249 দেয়
সম্পাদনা:
নেতিবাচক myInt1
মানগুলির জন্য অন্যান্য সংখ্যার সমাধানের মতো একই ত্রুটিটি বিবেচনা করে এর মতো কিছু করা সহজ হতে পারে:
int rem;
int div = Math.DivRem(myInt1, myInt2, out rem);
if (rem > 0)
div++;
এটি div
কেবলমাত্র পূর্ণসংখ্যার ক্রিয়াকলাপগুলিতে সঠিক ফলাফল দেয় ।
কারণ এটি ভুল : -1 এবং -5 এর 1 দেওয়া উচিত, এটি 0 দেয়
সম্পাদনা (আরও একবার, অনুভূতি সহ):
বিভাগ অপারেটরটি শূন্যের দিকে ঘুরবে; নেতিবাচক ফলাফলের জন্য এটি ঠিক সঠিক, সুতরাং কেবল অ-নেতিবাচক ফলাফলগুলির সমন্বয় প্রয়োজন। যাইহোক যেভাবে যাইহোক এবং DivRem
কেবল একটি করে তা বিবেচনা করে , আসুন কলটি এড়িয়ে চলুন (এবং যখন প্রয়োজন হয় না তখন মডুলো গণনা এড়াতে সহজ তুলনা দিয়ে শুরু করুন):/
%
int div = myInt1 / myInt2;
if ((div >= 0) && (myInt1 % myInt2 != 0))
div++;
কারণ এটি ভুল : -1 এবং 5 এর 0 দেওয়া উচিত, এটি 1 দেয়
(আমার নিজের সর্বশেষ প্রয়াসের প্রতিরক্ষায় আমি কখনই যুক্তিযুক্ত উত্তর চেষ্টা করা উচিত হয়নি যখন আমার মন আমাকে বলছিল যে আমি ঘুমের জন্য ২ ঘন্টা দেরি করেছি)
একটি এক্সটেনশন পদ্ধতি ব্যবহার করার উপযুক্ত সুযোগ:
public static class Int32Methods
{
public static int DivideByAndRoundUp(this int number, int divideBy)
{
return (int)Math.Ceiling((float)number / (float)divideBy);
}
}
এটি আপনার কোডকে উবারও পাঠযোগ্য করে তোলে:
int result = myInt.DivideByAndRoundUp(4);
আপনি একটি সহায়ক লিখতে পারে।
static int DivideRoundUp(int p1, int p2) {
return (int)Math.Ceiling((double)p1 / p2);
}
আপনি নিম্নলিখিত মত কিছু ব্যবহার করতে পারে।
a / b + ((Math.Sign(a) * Math.Sign(b) > 0) && (a % b != 0)) ? 1 : 0)
উপরের উত্তরগুলির কয়েকটি ফ্লোট ব্যবহার করে, এটি অদক্ষ এবং সত্যই প্রয়োজনীয় নয়। স্বাক্ষরবিহীন ints জন্য এটি int1 / int2 জন্য একটি কার্যকর উত্তর:
(int1 == 0) ? 0 : (int1 - 1) / int2 + 1;
স্বাক্ষরিত ইনটগুলির জন্য এটি সঠিক হবে না
এখানে সমস্ত সমাধানগুলির সাথে সমস্যাটি হ'ল তাদের একটি castালাই প্রয়োজন বা তাদের একটি সংখ্যাসূচক সমস্যা রয়েছে। ভাসা বা ডাবল কাস্ট করা সর্বদা একটি বিকল্প, তবে আমরা আরও ভাল করতে পারি।
আপনি যখন @ জেরিজেভিএল থেকে উত্তরের কোডটি ব্যবহার করবেন
int div = myInt1 / myInt2;
if ((div >= 0) && (myInt1 % myInt2 != 0))
div++;
একটি রাউন্ডিং ত্রুটি আছে। 1/5 টি গোল হয়ে যাবে, কারণ 1% 5! = 0. তবে এটি ভুল, কারণ রাউন্ডিং কেবল তখনই ঘটবে যদি আপনি 1 টি 3 এর সাথে প্রতিস্থাপন করেন, সুতরাং ফলাফলটি 0.6 হয়। আমাদের যখন গণনাটি 0.5 এর চেয়ে বড় বা তার সমান মান দেয় তখন রাউন্ড আপ করার জন্য আমাদের একটি উপায় অনুসন্ধান করতে হবে। উপরের উদাহরণের মডুলো অপারেটরের ফলাফলটির পরিধি 0 থেকে myInt2-1 পর্যন্ত রয়েছে। রাউন্ডিং কেবল তখনই ঘটতে পারে যখন বাকী অংশটি বিভাজকের 50% এর বেশি হয়। সুতরাং অ্যাডজাস্টেড কোডটি এর মতো দেখাচ্ছে:
int div = myInt1 / myInt2;
if (myInt1 % myInt2 >= myInt2 / 2)
div++;
অবশ্যই আমাদেরও আইএনটি 2/2 এ গোলাকার সমস্যা রয়েছে, তবে এই ফলাফলটি আপনাকে এই সাইটের অন্যান্যগুলির চেয়ে আরও ভাল গোলাকার সমাধান দেবে।