সি / সি ++ তে পূর্ণসংখ্যা বিভাগের দ্রুত সিলিং


262

প্রদত্ত পূর্ণসংখ্যার মান xএবং y, সি এবং সি ++ উভয়ই q = x/yভাসমান বিন্দুর সমতলের ভাগফল হিসাবে ফিরে আসে । আমি পরিবর্তে সিলিং ফেরার পদ্ধতিতে আগ্রহী। উদাহরণস্বরূপ, ceil(10/5)=2এবং ceil(11/5)=3

সুস্পষ্ট পদ্ধতির মধ্যে এমন কিছু জড়িত:

q = x / y;
if (q * y < x) ++q;

এটির জন্য একটি অতিরিক্ত তুলনা এবং গুণ প্রয়োজন; এবং অন্যান্য পদ্ধতিগুলি আমি দেখেছি (বাস্তবে ব্যবহৃত) একটি floatবা হিসাবে কাস্টিং জড়িত double। অতিরিক্ত গুন (বা দ্বিতীয় বিভাগ) এবং শাখা এড়ানো এমন আরও কোনও সরাসরি পদ্ধতি আছে এবং এটিও ভাসমান পয়েন্ট সংখ্যা হিসাবে কাস্টিং এড়ানো হয়?


70
বিভাজন নির্দেশটি প্রায়শই একই সাথে ভাগফল এবং বাকী উভয়ই একই সাথে ফেরত দেয় যাতে গুন করার প্রয়োজন নেই, কেবল q = x/y + (x % y != 0);যথেষ্ট
ফুক্লভি

2
@ LưuVĩnhPhúc এই মন্তব্যটির গ্রহণযোগ্য উত্তর হওয়া উচিত, ইমো।
আন্দ্রেয়াস গ্রেপেন্টিন

1
@ LưuVĩnhPhúc গুরুত্ব সহকারে আপনার এটিকে উত্তর হিসাবে যুক্ত করতে হবে। কোডলিটি পরীক্ষার সময় আমি আমার উত্তরের জন্য এটি ব্যবহার করেছি। এটি একটি মোহন মত কাজ করেছে যদিও আমি নিশ্চিত নই যে উত্তরের মোড অংশটি কীভাবে কাজ করে তবে এটি কাজটি করে।
জ্যাকারি ক্রাউস

2
লু ভান ফ্যাক উপরের মন্তব্যটি ছেড়ে যাওয়ার এক বছর আগে মিগুয়েল ফিগুয়েরিডো নীচের উত্তরটি অ্যান্ড্রেস গ্রাপেন্টিনের কাছে জমা দেওয়া হয়েছিল। মিগুয়েলের সমাধানটি কীভাবে আবেদনময়ী এবং মার্জিত সমাধান তা আমি বুঝতে পেরেছি, আমি এই শেষের দিকে গৃহীত উত্তরটি পরিবর্তন করতে আগ্রহী নই। উভয় পন্থা দৃ .় থাকে remain যদি আপনি এটি সম্পর্কে দৃ strongly়ভাবে মনে করেন তবে আমি প্রস্তাব দিচ্ছি যে আপনি নীচে মিগুএলের উত্তরটি ভোট দিয়ে আপনার সমর্থনটি দেখান।

1
আজব, আমি প্রস্তাবিত সমাধানগুলির কোনও বুদ্ধিমান পরিমাপ বা বিশ্লেষণ দেখিনি seen আপনি হাড়ের কাছাকাছি গতি সম্পর্কে কথা বলছেন, তবে স্থাপত্য, পাইপলাইন, শাখা নির্দেশাবলী এবং ঘড়ির চক্র সম্পর্কে কোনও আলোচনা নেই।
রাডো

উত্তর:


394

ধনাত্মক সংখ্যার জন্য

unsigned int x, y, q;

গোল করার জন্য ...

q = (x + y - 1) / y;

বা (এক্স + ওয়াইয়ের ওভারফ্লো এড়ানো)

q = 1 + ((x - 1) / y); // if x != 0

6
@ বিটক: নেতিবাচক সংখ্যার জন্য, আমি বিশ্বাস করি যে C99 বৃত্তাকার থেকে শূন্যকে নির্দিষ্ট করে, বিভাগের সিলিংও তাই x/y। C90 কীভাবে বৃত্তাকার তা নির্দিষ্ট করে নি এবং আমি মনে করি না যে বর্তমান সি ++ মানকটি হয়।
ডেভিড থর্নলি

6
: এরিক Lippert এর পোস্ট দেখুন stackoverflow.com/questions/921180/c-round-up/926806#926806
Mashmagar

3
দ্রষ্টব্য: এটি উপচে পড়তে পারে। q = ((দীর্ঘ দীর্ঘ) x + y - 1) / y হবে না। আমার কোডটি যদিও ধীরে ধীরে, তাই যদি আপনি জানেন যে আপনার নম্বরগুলি উপচে পড়বে না, আপনার স্পার্কির সংস্করণ ব্যবহার করা উচিত।
জর্জেন ফোগ

1
@ বিটক: আমি বিশ্বাস করি যে ডেভিডের বক্তব্যটি ছিল যদি ফলাফলটি নেতিবাচক হয় তবে আপনি উপরের গণনাটি ব্যবহার করবেন না - আপনি কেবল ব্যবহার করবেনq = x / y;
ক্যাফে

12
দ্বিতীয়টির একটি সমস্যা রয়েছে যেখানে x ০. সিল (0 / y) = 0 তবে এটি ফিরে আসে 1
ওমরি ইয়াদান

78

ধনাত্মক সংখ্যার জন্য:

    q = x/y + (x % y != 0);

5
বেশিরভাগ সাধারণ আর্কিটেকচারের বিভাজন নির্দেশিকায় এর ফলাফলের বাকী অংশও অন্তর্ভুক্ত থাকে সুতরাং এটি সত্যই কেবল একটি বিভাগ প্রয়োজন এবং খুব দ্রুত হবে
ফুক্লভি

58

স্পার্কির উত্তর হ'ল এই সমস্যাটি সমাধান করার একটি মানক উপায়, তবে আমি আমার মন্তব্যে যেমন লিখেছি, আপনি ওভারফ্লোসের ঝুঁকি চালান। আরও বিস্তৃত প্রকারটি ব্যবহার করে এটি সমাধান করা যেতে পারে তবে আপনি যদি বিভক্ত করতে চান তবে কী হবে long long?

নাথন আর্নস্টের উত্তরটি একটি সমাধান সরবরাহ করে তবে এটিতে একটি ফাংশন কল, একটি পরিবর্তনশীল ঘোষণা এবং শর্তসাপেক্ষ জড়িত, এটি এটি ওপিএস কোডের চেয়ে কম নয় এবং সম্ভবত আরও ধীরতর করে তোলে কারণ এটি অপ্টিমাইজ করা শক্ত।

আমার সমাধানটি হ'ল:

q = (x % y) ? x / y + 1 : x / y;

এটি ওপিএস কোডের তুলনায় কিছুটা দ্রুত হবে, কারণ প্রসেসরের উপর একই নির্দেশিকা ব্যবহার করে মডুলো এবং বিভাগ সঞ্চালিত হয়, কারণ সংকলক দেখতে পাবে যে তারা সমান। কমপক্ষে জিসিসি 4.4.1 x86--2 পতাকা সহ এই অপ্টিমাইজেশনটি সম্পাদন করে।

তাত্ত্বিকভাবে সংকলক নাথন আর্নস্টের কোডে ফাংশন কলটিকে ইনলাইন করতে পারে এবং একই জিনিসটি নির্গত করতে পারে, তবে আমি যখন পরীক্ষা করেছিলাম তখন জিসিসি তা করেনি। এটি হতে পারে কারণ এটি সংমিত কোডটি স্ট্যান্ডার্ড লাইব্রেরির একক সংস্করণে টাই করবে।

একটি চূড়ান্ত নোট হিসাবে, আধুনিক মেশিনে এর কোনও কিছুই বিবেচনা করে না, যদি আপনি চূড়ান্তভাবে লুপে থাকেন এবং আপনার সমস্ত ডেটা রেজিস্টারে বা এল 1-ক্যাশে থাকে তবে। অন্যথায় এই সমস্ত সমাধানগুলি সমানভাবে দ্রুত হবে, সম্ভবত নাথন আর্নস্টের ব্যতীত, যদি ফাংশনটি মূল স্মৃতি থেকে আনতে হয় তবে উল্লেখযোগ্যভাবে ধীর হতে পারে।


3
ওভারফ্লো ঠিক করার সহজ উপায় ছিল, কেবল y / y হ্রাস করুন:q = (x > 0)? 1 + (x - 1)/y: (x / y);
বেন ভয়েগট

-১: এটি একটি অদক্ষ উপায়, কারণ এটি ব্যয়বহুল% এর জন্য সস্তা *; ওপি পদ্ধতির চেয়েও খারাপ।
ইয়ভেস দাউস্ট

2
না, তা হয় না। আমি উত্তরে যেমনটি ব্যাখ্যা করেছি, আপনি ইতিমধ্যে বিভাগ সম্পাদন করার সময়% অপারেটর মুক্ত হয়।
জর্জেন ফোগ

1
তাহলে q = x / y + (x % y > 0);ভাবের চেয়ে সহজ ? :?
হান

এটি "সহজ" দ্বারা আপনি কী বোঝাতে চান তার উপর নির্ভর করে। কম্পাইলার কীভাবে এটি অনুবাদ করে তার উপর নির্ভর করে এটি দ্রুত বা নাও হতে পারে। আমার অনুমানটি ধীর হবে তবে এটি নিশ্চিত হওয়ার জন্য আমাকে এটি পরিমাপ করতে হবে।
জার্জেন ফাগ

18

আপনি divসিটিডলাইবে ফাংশনটি একক কলটিতে ভাগ এবং বাকী অংশ পেতে ব্যবহার করতে পারেন এবং তারপরে নীচের মতো আলাদাভাবে সিলিংটি পরিচালনা করতে পারেন

#include <cstdlib>
#include <iostream>

int div_ceil(int numerator, int denominator)
{
        std::div_t res = std::div(numerator, denominator);
        return res.rem ? (res.quot + 1) : res.quot;
}

int main(int, const char**)
{
        std::cout << "10 / 5 = " << div_ceil(10, 5) << std::endl;
        std::cout << "11 / 5 = " << div_ceil(11, 5) << std::endl;

        return 0;
}

12
ডাবল ব্যাং একটি আকর্ষণীয় ক্ষেত্রে হিসাবে, আপনি এছাড়াও করতে পারেন return res.quot + !!res.rem;:)
স্যাম হারওয়েল

Ldiv সর্বদা আর্গুমেন্ট দীর্ঘ দীর্ঘায়িত করে না? এবং এতে কোনও খরচ হয় না, আপ-কাস্টিং বা ডাউন-ingালাই?
einpoklum

12

এ কেমন? (y অ-নেতিবাচক প্রয়োজন, তাই এটি বিরল ক্ষেত্রে এটি ব্যবহার করবেন না যেখানে y কোনও নে-নেগ্রাভিটি গ্যারান্টি সহ পরিবর্তনশীল)

q = (x > 0)? 1 + (x - 1)/y: (x / y);

আমি y/yএকটিতে কমেছি, শব্দটি সরিয়ে x + y - 1এবং এটির সাথে কোনও প্রবাহের কোনও সম্ভাবনা নেই।

আমি x - 1যখন xস্বাক্ষরবিহীন টাইপ হয় এবং শূন্য থাকে তখন আমার চারপাশে মোড়ানো এড়ানো হয়।

স্বাক্ষরিত x, নেতিবাচক এবং শূন্য এখনও একক ক্ষেত্রে একত্রিত।

সম্ভবত আধুনিক সাধারণ উদ্দেশ্যে সিপিইউতে কোনও বিশাল সুবিধা নয়, তবে এম্বেডড সিস্টেমে এটি অন্যান্য সঠিক উত্তরের চেয়ে আরও দ্রুত হবে।


আপনার অন্য সবসময় 0 ফিরে আসবে, কোনও কিছুর গণনা করার দরকার নেই।
রুড আলথুইজেন

@ রুদ: সত্য নয়। X = -45 এবং y = 4 বিবেচনা করুন
বেন ভয়েইট

7

ইতিবাচক এবং নেতিবাচক উভয়ের জন্যই একটি সমাধান রয়েছে xতবে কেবলমাত্র y1 বিভাগ এবং শাখা ছাড়াই ইতিবাচক জন্য :

int ceil(int x, int y) {
    return x / y + (x % y > 0);
}

নোট, যদি x ইতিবাচক হয় তবে বিভাগটি শূন্যের দিকে থাকে এবং অনুস্মারকটি শূন্য না হলে আমাদের 1 যুক্ত করা উচিত।

যদি xনেতিবাচক হয় তবে বিভাগটি শূন্যের দিকে থাকে, এটি আমাদের প্রয়োজন, এবং আমরা কোনও কিছু যুক্ত করব না কারণ x % yইতিবাচক নয়


আকর্ষণীয়, কারণ y ধ্রুবক থাকার ক্ষেত্রে প্রচলিত ঘটনা রয়েছে
ওল্ফ

1
মোডের বিভাজন প্রয়োজন তাই এটি কেবল এখানে 1 বিভাগ নয়, তবে সংকলক দুটি অনুরূপ বিভাগকে একটিতে অনুকূল করতে পারেন।
এমকাজেম আখগারি

4

এটি ইতিবাচক বা নেতিবাচক সংখ্যার জন্য কাজ করে:

q = x / y + ((x % y != 0) ? !((x > 0) ^ (y > 0)) : 0);

যদি একটি বাকি নেই, চেক কিনা তা দেখতে xএবং yএকই চিহ্নের এবং যোগ 1নেই।


3

আমি বরং মন্তব্য করতে চাই তবে আমার কাছে উচ্চ পর্যায়ে কোনও প্রতিনিধি নেই।

আমি যতদূর অবগত, ইতিবাচক যুক্তি এবং একটি বিভাজকের জন্য যা 2 এর শক্তি, এটি সবচেয়ে দ্রুতগতিতে (সিইউডিএতে পরীক্ষিত):

//example y=8
q = (x >> 3) + !!(x & 7);

শুধুমাত্র জেনেরিক ইতিবাচক যুক্তিগুলির জন্য, আমি এটি এর মতো করে প্রবণতা করি:

q = x/y + !!(x % y);

সমসাময়িক সিউডিএ-তে কীভাবে সমাধানগুলি কার্যকারিতা অনুসারে q = x/y + !!(x % y);দাঁড় করায় q = x/y + (x % y == 0);এবং তা দেখতে আকর্ষণীয় হবে q = (x + y - 1) / y;
গ্রেগ ক্রমিদা


-2

ও 3 দিয়ে সংকলন করুন, সংকলকটি অপ্টিমাইজেশনটি ভাল সম্পাদন করে।

q = x / y;
if (x % y)  ++q;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.