কার্যকর স্বাক্ষরযুক্ত-স্বাক্ষরিত কাস্ট বাস্তবায়ন-সংজ্ঞায়িত আচরণ এড়ানো iding


94

আমি একটি ফাংশন সংজ্ঞায়িত করতে চাই যা unsigned intআর্গুমেন্ট হিসাবে গ্রহণ করে এবং যুক্তির জন্য একটি intসম্মিলিত Modulo UINT_MAX + 1 প্রদান করে।

প্রথম চেষ্টাটি দেখতে এরকম হতে পারে:

int unsigned_to_signed(unsigned n)
{
    return static_cast<int>(n);
}

তবে যে কোনও ভাষার আইনজীবী জানেন, INT_MAX এর চেয়ে বড় মানের জন্য স্বাক্ষরযুক্ত থেকে স্বাক্ষর করা প্রয়োগ-সংজ্ঞায়িত।

আমি এটিকে বাস্তবায়িত করতে চাই যে (ক) এটি কেবল অনুমানের দ্বারা বাধ্যতামূলক আচরণের উপর নির্ভর করে; এবং (খ) এটি যে কোনও আধুনিক মেশিনে কোনও সংযোজন এবং সংকলককে অনুকূলকরণের মধ্যে সংকলন করে।

উদ্ভট মেশিনগুলির জন্য ... স্বাক্ষরযুক্ত স্বাক্ষরের জন্য যদি স্বাক্ষরযুক্ত কোনও সংঘের মডেল UINT_MAX + 1 না থাকে তবে ধরা যাক আমি একটি ব্যতিক্রম ছুঁড়ে দিতে চাই। যদি একের বেশি থাকে (তবে আমি নিশ্চিত যে এটি সম্ভব) তবে আসুন আমরা বলি যে আমি সবচেয়ে বড় চাই।

ঠিক আছে, দ্বিতীয় প্রচেষ্টা:

int unsigned_to_signed(unsigned n)
{
    int int_n = static_cast<int>(n);

    if (n == static_cast<unsigned>(int_n))
        return int_n;

    // else do something long and complicated
}

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

এখন, এই দ্বিতীয় প্রচেষ্টাটি আমি যা চাই তার কাছাকাছি। যদিও কাস্টে intকিছু ইনপুটগুলির জন্য বাস্তবায়ন-সংজ্ঞায়িত করা হয়েছে, তবে কাস্ট করতে unsignedব্যাকটিকে মান মডিউল UINT_MAX + 1 সংরক্ষণের মান দ্বারা গ্যারান্টিযুক্ত। সুতরাং শর্তসাপেক্ষে আমি যা চাই ঠিক তা যাচাই করে না এবং এটি আমার মুখোমুখি হওয়ার মতো কোনও সিস্টেমে সংকলিত হবে।

তবে ... আমি intএটি এখনও বাস্তবায়ন-সংজ্ঞায়িত আচরণের জন্য প্রার্থনা করব কিনা তা আগে পরীক্ষা না করেই কাস্ট করছি । 2050 সালে কিছু অনুমানমূলক সিস্টেমে এটি কে-জানে-কী করতে পারে। সুতরাং আসুন আমি এটি এড়াতে চাই বলি।

প্রশ্ন: আমার "তৃতীয় প্রচেষ্টা" দেখতে কেমন হবে?

পুনরুদ্ধার করতে, আমি চাই:

  • স্বাক্ষরবিহীন অন্তর্ভুক্ত থেকে স্বাক্ষর করা ইন কাস্ট করুন
  • UINT_MAX + 1 মানটি সংরক্ষণ করুন
  • কেবল মান-বাধ্যতামূলক আচরণটি চালান
  • সংযোজকটি অনুকূলকরণের সাথে একটি আদর্শ দুটি দ্বিগুণ-পরিপূরক মেশিনে একটি অন-সংকলন করুন

[হালনাগাদ]

এটি কেন তুচ্ছ প্রশ্ন নয় তা দেখানোর জন্য আমি একটি উদাহরণ দিই।

নিম্নলিখিত বৈশিষ্ট্য সহ একটি অনুমান সি ++ বাস্তবায়ন বিবেচনা করুন:

  • sizeof(int) সমান 4
  • sizeof(unsigned) সমান 4
  • INT_MAX সমান 32767
  • INT_MINসমান -2 32 + 32768
  • UINT_MAXসমান 2 32 - 1
  • পাটিগণিত উপর intমডিউল 2 32 (পরিসীমা মধ্যে INT_MINদিয়ে INT_MAX)
  • std::numeric_limits<int>::is_modulo সত্য
  • স্বাক্ষরযুক্ত স্বাক্ষর না nকরা কাস্ট করা 0 <= n <= 32767 এর মান সংরক্ষণ করে এবং অন্যথায় শূন্য দেয়

এই intহাইপোটিকাল বাস্তবায়নের ক্ষেত্রে প্রতিটি unsignedমানের জন্য ঠিক এক মান সম্মত (Mod UINT_MAX + 1) থাকে । সুতরাং আমার প্রশ্নটি সঠিকভাবে সংজ্ঞায়িত হবে।

আমি দাবি করি যে এই হাইপোথটিক্যাল সি ++ বাস্তবায়ন সি ++ 98, সি ++ 03 এবং সি ++ 11 টি নির্দিষ্টকরণের সাথে পুরোপুরি মেনে চলে। আমি স্বীকার করি আমি সেগুলির প্রত্যেকটি শব্দ মুখস্থ করতে পারি নি ... তবে আমি বিশ্বাস করি আমি প্রাসঙ্গিক বিভাগগুলি মনোযোগ সহকারে পড়েছি। সুতরাং আপনি যদি আমার উত্তরটি গ্রহণ করতে চান তবে আপনাকে অবশ্যই (ক) এমন অনুমানের কথা উল্লেখ করতে হবে যা এই অনুমান বাস্তবায়নকে বাতিল করে দেয় বা (খ) এটিকে সঠিকভাবে পরিচালনা করবে।

প্রকৃতপক্ষে, একটি সঠিক উত্তর অবশ্যই মান দ্বারা অনুমোদিত প্রতিটি অনুমানমূলক বাস্তবায়ন পরিচালনা করতে হবে । সংজ্ঞা অনুসারে এটিই "কেবলমাত্র মান-বাধ্যতামূলক আচরণের আহ্বান করুন" এর অর্থ।

ঘটনাক্রমে, নোট যে std::numeric_limits<int>::is_moduloএকাধিক কারণে এখানে সম্পূর্ণ বেহুদা। একটি জিনিসের জন্য, এটি trueস্বাক্ষরযুক্ত-স্বাক্ষরিত কাস্টগুলি বৃহত্তর স্বাক্ষরিত মানগুলির জন্য কাজ না করলেও তা হতে পারে । অন্যটির জন্য, এটি কারও trueপরিপূরক বা সাইন-প্রস্থের সিস্টেমেও হতে পারে, যদি গাণিতিকটি কেবল পুরো পূর্ণসংখ্যার পরিসীমাটি মডিউল করে। ইত্যাদি। আপনার উত্তর যদি নির্ভর করে তবে is_moduloএটি ভুল।

[আপডেট 2]

এইচডিডি এর উত্তর আমাকে কিছু শিখিয়েছে: আমার পূর্ণসংখ্যার জন্য সি ++ বাস্তবায়ন আধুনিক সি দ্বারা অনুমোদিত নয় সি 99 এবং সি 11 মান স্বাক্ষরিত পূর্ণসংখ্যার উপস্থাপনা সম্পর্কে খুব নির্দিষ্ট; প্রকৃতপক্ষে, তারা কেবল দ্বিগুণ-পরিপূরক, পরিপূরক, এবং সাইন-প্রস্থের (বিভাগ 6.2.6.2 অনুচ্ছেদ (2);) অনুমতি দেয়।

তবে সি ++ সি নয়, যেমনটি দেখা যাচ্ছে, এই ঘটনাটি আমার প্রশ্নের একেবারে কেন্দ্রবিন্দুতে lies

মূল সি ++ 98 স্ট্যান্ডার্ডটি অনেক পুরানো সি 98 এর উপর ভিত্তি করে তৈরি হয়েছিল, যা বলে (বিভাগ 3.1.2.5):

স্বাক্ষরিত প্রতিটি পূর্ণসংখ্যার প্রকারের জন্য, স্বাক্ষরযুক্ত স্বাক্ষরযুক্ত পূর্ণসংখ্যার টাইপ (স্বাক্ষরবিহীন কীওয়ার্ড দিয়ে মনোনীত) থাকে যা সমান পরিমাণ স্টোরেজ (সাইন ইন তথ্য সহ) ব্যবহার করে এবং একই রকম প্রান্তিককরণের প্রয়োজনীয়তা রয়েছে। একটি স্বাক্ষরিত পূর্ণসংখ্যার ধরণের অব্যবহৃত মানগুলির সীমাটি স্বাক্ষরযুক্ত স্বাক্ষরিত পূর্ণসংখ্যা টাইপের একটি সাবরেঞ্জ এবং প্রতিটি ধরণের একই মানের প্রতিনিধিত্ব একই।

সি 89 কেবলমাত্র একটি সাইন বিট থাকার বা কেবল দ্বি-পরিপূরক / বেশী-পরিপূরক / সাইন-প্রস্থের অনুমতি দেওয়ার বিষয়ে কিছুই বলে না।

সি ++ 98 স্ট্যান্ডার্ড প্রায় ভাষাটি এই ভাষাটি গ্রহণ করেছে (বিভাগ 3.9.1 অনুচ্ছেদ (3)):

স্বাক্ষরিত প্রতিটি পূর্ণসংখ্যার ধরণের জন্য, একটি স্বাক্ষরযুক্ত (তবে ভিন্ন) স্বাক্ষরযুক্ত পূর্ণসংখ্যার টাইপ রয়েছে : " unsigned char", " unsigned short int", " unsigned int" এবং " unsigned long int", যার প্রত্যেকটিতে একই পরিমাণ সঞ্চয়স্থান রয়েছে এবং একই প্রান্তিককরণের প্রয়োজনীয়তা রয়েছে (3.9) ) সম্পর্কিত স্বাক্ষরিত পূর্ণসংখ্যা টাইপ হিসাবে; এটি হ'ল প্রতিটি স্বাক্ষরিত পূর্ণসংখ্যার টাইপটির সাথে সম্পর্কিত স্বাক্ষরযুক্ত পূর্ণসংখ্যা টাইপের মতো একই অবজেক্টের উপস্থাপনা থাকে । একটি স্বাক্ষরিত পূর্ণসংখ্যার ধরণের অবৈধ মানগুলির সীমাটি স্বাক্ষরিত স্বাক্ষরযুক্ত পূর্ণসংখ্যা টাইপের একটি সাবরেঞ্জ এবং প্রতিটি স্বাক্ষরিত / স্বাক্ষরবিহীন প্রকারের মান প্রতিনিধিত্ব একই হবে।

সি ++ 03 স্ট্যান্ডার্ড মূলত অভিন্ন ভাষা ব্যবহার করে, যেমন সি ++ 11 করে।

যতটা আমি বলতে পারি কোনও মানক সি ++ স্পেস তার স্বাক্ষরিত পূর্ণসংখ্যার উপস্থাপনাটিকে কোনও সি স্পিকে সীমাবদ্ধ করে না। এবং একক চিহ্ন বিট বা ধরণের কিছু বাধ্যতামূলক করার কিছুই নেই। কেবলমাত্র এটিই বলে যে অ-নেতিবাচক স্বাক্ষরিত পূর্ণসংখ্যাগুলি অবশ্যই স্বাক্ষরবিহীন স্বাক্ষরযুক্ত সাব্রিজ হতে হবে।

সুতরাং, আমি আবার দাবি করি যে INT_MIN = -2 32 +32768 সহ INT_MAX = 32767 অনুমোদিত। যদি আপনার উত্তরটি অন্যথায় ধরে নেওয়া হয়, তবে আপনি ভুল সি প্রমাণিত কোনও সি ++ না দিলে এটি ভুল।


@ স্টিভ জেসাপ: আসলে, আমি সেই ক্ষেত্রে আমি যা চাই ঠিক তা বলেছি: "যদি স্বাক্ষরযুক্ত স্বাক্ষরের কোনও স্বাক্ষরযুক্ত মেনডুল ইউএনআইএনএমএএমএক্স + 1 না থাকে, তবে আমি বলি যে আমি একটি ব্যতিক্রম ছুঁড়ে দিতে চাই।" এটি হ'ল আমি "ডান" স্বাক্ষরিত ইনট চাই যা বিদ্যমান থাকে। যদি এটি বিদ্যমান না থাকে - যেমন প্যাডিং বিট বা একাধিক পরিপূরক উপস্থাপনাগুলির ক্ষেত্রে ঘটতে পারে - আমি এটি সনাক্ত করতে এবং সেই কাস্টের বিশেষ অনুরোধের জন্য এটি পরিচালনা করতে চাই।
নিমো

দুঃখিত, আমি কীভাবে এটি মিস করেছি তা নিশ্চিত নই।
স্টিভ জেসোপ

বিটিডব্লু, আমি মনে করি যে আপনার অনুমানমূলক কৌতুক বাস্তবায়নের intজন্য এটি উপস্থাপনের জন্য কমপক্ষে 33 বিট প্রয়োজন। আমি জানি এটি কেবল একটি পাদটীকা, সুতরাং আপনি এটি অ-আদর্শিক তর্ক করতে পারেন, তবে আমি মনে করি সি ++ 11 এর পাদটীকা 49 সত্য বলে অভিহিত হয়েছে (যেহেতু এটি স্ট্যান্ডার্ডে ব্যবহৃত একটি শব্দের সংজ্ঞা) এবং এটি বিপরীত নয় আদর্শ পাঠ্যে স্পষ্টভাবে কিছু বলা হয়েছে। সুতরাং সমস্ত নেতিবাচক মানগুলি অবশ্যই একটি বিট প্যাটার্নের দ্বারা প্রতিনিধিত্ব করতে হবে যাতে সর্বোচ্চ বিট সেট করা থাকে এবং তাই আপনি 2^32 - 32768সেগুলি 32 টি বিটগুলিতে ক্র্যাম করতে পারবেন না । আপনার যুক্তি আকারের উপর কোনওভাবে নির্ভর করে না int
স্টিভ জেসোপ

এবং এইচডিডি এর উত্তরে আপনার সম্পাদনাগুলি সম্পর্কে, আমি মনে করি আপনি 49 নোটটি ভুল ব্যাখ্যা করেছেন You আপনি বলেছেন যে সাইন-প্রবণতা নিষিদ্ধ, তবে তা নয়। আপনি এটিকে পড়েছেন: "ধারাবাহিক বিট দ্বারা প্রতিনিধিত্ব করা মানগুলি সংযোজনীয় হয়, 1 দিয়ে শুরু হয় এবং (সম্ভবত সর্বোচ্চ অবস্থানের বিট বাদে 2 এর ক্রমাগত অবিচ্ছেদ্য শক্তি দ্বারা গুণিত হয়)"। আমি বিশ্বাস করি এটি পড়া উচিত, "পরের বিটগুলি দ্বারা প্রতিনিধিত্ব করা মানগুলি (যুক্ত হয়, 1 দিয়ে শুরু হয় এবং 2 এর ধারাবাহিক অবিচ্ছেদ্য শক্তি দ্বারা গুণিত হয়), সম্ভবত উচ্চতর অবস্থানের বিট বাদে"। অর্থাৎ উচ্চ বিট সেট করা থাকলে সমস্ত বেট বন্ধ রয়েছে।
স্টিভ জেসপ

@ স্টিভ জেসোপ: আপনার ব্যাখ্যাটি সঠিক হতে পারে। যদি তা হয় তবে তা আমার অনুমানকে বাতিল করে দেয় ... তবে এটি সত্যিকারের বিশাল সংখ্যক সম্ভাবনারও পরিচয় দেয়, এই প্রশ্নের উত্তর দেওয়া অত্যন্ত কঠিন করে তোলে। এটিকে আসলে আমার কাছে একটি বাগের মতো দেখাচ্ছে। (স্পষ্টতই, সি কমিটি এটি ভেবেছিল এবং সি 99 এটিকে তীব্রভাবে স্থির করেছিল I আমি অবাক হয়েছি কেন কেন সি ++ 11 তাদের পন্থা অবলম্বন করেনি?)
নেমো

উত্তর:


70

ব্যবহারকারী 71404 এর উত্তরটি প্রসারিত করছে:

int f(unsigned x)
{
    if (x <= INT_MAX)
        return static_cast<int>(x);

    if (x >= INT_MIN)
        return static_cast<int>(x - INT_MIN) + INT_MIN;

    throw x; // Or whatever else you like
}

যদি x >= INT_MIN(পদোন্নতির নিয়মগুলি মাথায় INT_MINরাখেন, এতে রূপান্তরিত হন unsigned), তবে এর x - INT_MIN <= INT_MAXফলে আর কোনও ওভারফ্লো হবে না।

যদি তা সুস্পষ্ট না হয় x >= -4u, তবে "যদি , তবে x + 4 <= 3।" দাবিটি একবার দেখুন , এবং মনে রাখবেন যে INT_MAXকমপক্ষে -INT_MIN - 1 এর গাণিতিক মানের সমান হবে।

সর্বাধিক প্রচলিত সিস্টেমগুলিতে, যেখানে !(x <= INT_MAX)বোঝানো হয়েছে x >= INT_MIN, অপ্টিমাইজারটি দ্বিতীয় চেকটি সরাতে (এবং আমার সিস্টেমে সক্ষম) সক্ষম হওয়া উচিত, এটি নির্ধারণ করুন যে দুটি returnবিবৃতি একই কোডে সংকলিত হতে পারে এবং প্রথম চেকটিও মুছে ফেলতে পারে। উত্পন্ন সমাবেশ তালিকা:

__Z1fj:
LFB6:
    .cfi_startproc
    movl    4(%esp), %eax
    ret
    .cfi_endproc

আপনার প্রশ্নে কাল্পনিক বাস্তবায়ন:

  • INT_MAX সমান 32767
  • INT_MIN সমান -2 32 + 32768

সম্ভব নয়, তাই বিশেষ বিবেচনার প্রয়োজন নেই। INT_MINউভয় -INT_MAXবা সমান হবে -INT_MAX - 1। এটি সি এর পূর্ণসংখ্যার প্রকারের উপস্থাপনা (6.2.6.2) থেকে অনুসরণ করে, যার জন্য nবিটকে মান বিট হতে হবে, একটি বিটকে একটি সাইন বিট হতে হবে এবং কেবল একটি একক ফাঁদ উপস্থাপনের অনুমতি দেয় (প্যাডিং বিটের কারণে অবৈধ উপস্থাপনা সহ নয়), যাহা হ'ল অন্যটি নেতিবাচক শূন্য / উপস্থাপন করবে -INT_MAX - 1। সি ++ সি এর অনুমতি দেয় এমন কিছুর বাইরে কোনও পূর্ণসংখ্যার উপস্থাপনার অনুমতি দেয় না।

আপডেট : মাইক্রোসফ্ট সংকলক স্পষ্টতই এটি লক্ষ্য করে নাx > 10এবংx >= 11একই জিনিসটি পরীক্ষাকরে না। এটি কেবলমাত্রx >= INT_MINপরিবর্তিতহলে কাঙ্ক্ষিত কোড উত্পন্ন করেx > INT_MIN - 1u, এটি এটিx <= INT_MAX(এই প্ল্যাটফর্মের)অবহেলা হিসাবে সনাক্ত করতে পারে।

[নীচে আমাদের আলোচনার বিবরণ দিয়ে প্রশ্নকর্তা (নিমো) থেকে আপডেট করুন]

আমি এখন বিশ্বাস করি যে এই উত্তরটি সব ক্ষেত্রে কার্যকর হয় তবে জটিল কারণে for আমি এই সমাধানটির জন্য অনুগ্রহটি প্রদান করব, তবে যে কেউ যত্নবান না হলে আমি সমস্ত অযৌক্তিক বিবরণ ক্যাপচার করতে চাই।

আসুন সি ++ 11, বিভাগ 18.3.3 দিয়ে শুরু করুন:

টেবিল 31 শিরোনাম বর্ণনা করে <climits>

...

সামগ্রীগুলি স্ট্যান্ডার্ড সি লাইব্রেরির শিরোনামের মতো <limits.h>

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

যেহেতু সি ++ 11 সি <climits>99 থেকে ম্যাক্রোগুলিকে উত্তরাধিকারী করেছে , INT_MIN হয় -INT_MAX বা -INT_MAX-1 হয় এবং এইচভিডির কোডটি কাজের গ্যারান্টিযুক্ত। (দ্রষ্টব্য, প্যাডিংয়ের কারণে, INT_MAX UINT_MAX / 2 এর চেয়ে অনেক কম হতে পারে ... তবে স্বাক্ষরযুক্ত-> স্বাক্ষরযুক্ত কাস্তে কাজ করার জন্য ধন্যবাদ, এই উত্তরটি সেই জরিমানা পরিচালনা করে))

সি ++ 03 / সি ++ 98 টি জটিল। এটি <climits>"স্ট্যান্ডার্ড সি" থেকে উত্তরাধিকারী হওয়ার জন্য একই শব্দ ব্যবহার করে তবে এখন "স্ট্যান্ডার্ড সি" এর অর্থ সি 89 / সি 90।

এই সমস্ত - সি ++ 98, সি ++ 03, সি 98 / সি 90 - আমার প্রশ্নে আমি যে শব্দটি দিয়েছি তা রয়েছে তবে এটিও অন্তর্ভুক্ত করুন (সি ++ 03 বিভাগ 3.9.1 অনুচ্ছেদ 7):

অবিচ্ছেদ্য ধরনের উপস্থাপনা একটি বিশুদ্ধ বাইনারি সংখ্যাপাতকরণ সিস্টেম ব্যবহার দ্বারা মান নির্ধারণ করিবে (44)। [ উদাহরণ । এই ইন্টারন্যাশনাল স্ট্যান্ডার্ড সম্পূরক 2 এর 1 এর সম্পূরক এবং অবিচ্ছেদ্য ধরনের জন্য সাইন ইন মাত্রার উপস্থাপনা অনুমতি দেয়]

পাদটীকা (44) "খাঁটি বাইনারি সংখ্যা সিস্টেম" সংজ্ঞায়িত করেছে:

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

এই শব্দটি সম্পর্কে আকর্ষণীয় বিষয়টি এটি নিজের সাথে স্ববিরোধিতা করে, কারণ "খাঁটি বাইনারি সংখ্যা সিস্টেম" সংজ্ঞাটি কোনও চিহ্ন / মাত্রার প্রতিনিধিত্বের অনুমতি দেয় না! এটি উচ্চ বিটটিকে মান -2 এন -1 (দ্বিগুণ পরিপূরক) বা - (2 এন -1 -1) (যা পরিপূরক) হিসাবে অনুমতি দেয় না। তবে উচ্চ বিটের কোনও মূল্য নেই যা সাইন / মাত্রায় ফলাফল দেয়।

যাইহোক, আমার "অনুমানমূলক বাস্তবায়ন" এই সংজ্ঞার অধীনে "খাঁটি বাইনারি" হিসাবে যোগ্যতা অর্জন করে না, তাই এটি অস্বীকার করা হয়।

তবে, উচ্চ বিটটি হ'ল বিশেষ অর্থ হ'ল আমরা এটিকে যে কোনও মূল্যের অবদান রাখার কল্পনা করতে পারি: একটি ছোট ধনাত্মক মান, বিশাল ধনাত্মক মান, ছোট নেতিবাচক মান বা বিশাল নেতিবাচক মান। (যদি সাইন বিট অবদান রাখতে পারে - (2 এন -1 -1), কেন নয় - (2 এন -1 -2)? ইত্যাদি)

সুতরাং, আসুন একটি স্বাক্ষরিত পূর্ণসংখ্যার উপস্থাপনাটি কল্পনা করুন যা "চিহ্ন" বিটকে একটি বেহাল মান নির্ধারণ করে।

সাইন বিটের জন্য একটি সামান্য ধনাত্মক মান ফলাফল intহিসাবে ইতিবাচক পরিসীমা (সম্ভবত হিসাবে বৃহত্তর unsigned) হতে পারে , এবং এইচভিডির কোডটি ঠিক সূক্ষ্মভাবে পরিচালনা করে।

সাইন বিটের জন্য একটি বিশাল ধনাত্মক মানটির ফলে intসর্বাধিক বৃহত্তর unsignedপরিমাণ থাকবে যা নিষিদ্ধ।

সাইন বিটের জন্য একটি বিশাল নেতিবাচক মান ফলাফলের ক্ষেত্রে intএকটি অ-সংলগ্ন মানের প্রতিনিধিত্ব করতে সক্ষম হবে এবং সেই নির্দিষ্ট নিয়মের মধ্যে অন্যান্য শব্দের সাথে রয়েছে।

পরিশেষে, কীভাবে একটি সংকেত বিট সম্পর্কে যে একটি ছোট নেতিবাচক পরিমাণ অবদান রাখে? আমরা কী "সাইন বিট" তে অবদান রাখতে পারি, বলুন, ইন-এর মানকে? তাহলে INT_MAX হবে (বলুন) 2 31 -1 এবং INT_MIN হবে -37?

এর ফলে কয়েকটি সংখ্যার দুটি উপস্থাপনা থাকবে ... তবে পরিপূরক শূন্যকে দুটি উপস্থাপনা দেয় এবং এটি "উদাহরণ" অনুসারে অনুমোদিত। কোথাও অনুমানটি বলে না যে শূন্যই একমাত্র পূর্ণসংখ্যা যার দুটি উপস্থাপনা থাকতে পারে। সুতরাং আমি মনে করি এই নতুন অনুমানকে অনুমিত দ্বারা অনুমোদিত।

প্রকৃতপক্ষে, -1 থেকে নীচের যে কোনও নেতিবাচক মানটি -INT_MAX-1"সাইন বিট" এর মান হিসাবে অনুমোদিত বলে মনে হয় তবে এর চেয়ে ছোট কিছু হয় না (পাছে পরিধিটি স্বতঃস্ফূর্ত হতে পারে)। অন্য কথায়, -1 INT_MINথেকে কিছু হতে পারে -INT_MAX-1

এখন, কি অনুমান? বাস্তবায়ন-সংজ্ঞায়িত আচরণ এড়ানোর জন্য এইচভিডির কোডে দ্বিতীয় কাস্টের জন্য আমাদের কেবল এর x - (unsigned)INT_MINচেয়ে কম বা সমান প্রয়োজন INT_MAX। আমরা ঠিক দেখিয়েছি INT_MINঅন্তত -INT_MAX-1। অবশ্যই, xসর্বাধিক হয় UINT_MAX। স্বাক্ষরবিহীন একটি নেতিবাচক নম্বর কাস্ট করা যোগ হিসাবে সমান UINT_MAX+1। সব একসাথে রাখুন:

x - (unsigned)INT_MIN <= INT_MAX

যদি এবং কেবল যদি

UINT_MAX - (INT_MIN + UINT_MAX + 1) <= INT_MAX
-INT_MIN-1 <= INT_MAX
-INT_MIN <= INT_MAX+1
INT_MIN >= -INT_MAX-1

এটি সর্বশেষ যা আমরা স্রেফ দেখিয়েছি তাই এই বিকৃত ক্ষেত্রেও কোডটি আসলে কাজ করে।

এটি সমস্ত সম্ভাবনাকে ক্লান্ত করে তোলে, এইভাবে এই চূড়ান্ত একাডেমিক মহড়া শেষ করে।

নীচের লাইন: C89 / C90 তে স্বাক্ষরিত পূর্ণসংখ্যার জন্য কিছু গুরুতরভাবে নীচে নির্দিষ্ট আচরণ রয়েছে যা C ++ 98 / C ++ 03 দ্বারা উত্তরাধিকার সূত্রে প্রাপ্ত হয়েছে। এটি সি 99 এ স্থির করা হয়েছে এবং সি ++ 11 অপ্রত্যক্ষভাবে সি <limits.h>99 থেকে অন্তর্ভুক্ত করে ফিক্সটির উত্তরাধিকার সূত্রে প্রাপ্ত । এমনকি সি ++ 11 স্ব-বিরোধী "খাঁটি বাইনারি উপস্থাপনা" শব্দবন্ধকে ধরে রাখে ...


প্রশ্ন আপডেট হয়েছে। অন্যকে নিরুৎসাহিত করার জন্য আমি এই উত্তরটি (আপাতত) ডাউন-ভোটা করছি ... আমি পরে আন-ডাউন ভোট দেব কারণ উত্তর আকর্ষণীয়। (সি এর জন্য সঠিক, তবে সি ++ এর জন্য ভুল I আমি মনে করি))
নিমো

@ নেমো এই ক্ষেত্রে সি স্ট্যান্ডার্ড সি ++ এর জন্য প্রযোজ্য; খুব কমপক্ষে, মানগুলি <limits.h>সি ++ স্ট্যান্ডার্ডে সি স্ট্যান্ডার্ডের মতো একই অর্থযুক্ত হিসাবে সংজ্ঞায়িত হয়, সুতরাং সি এর সমস্ত প্রয়োজনীয়তাগুলির জন্য INT_MINএবং INT_MAXসি ++ এ উত্তরাধিকার সূত্রে প্রাপ্ত হয়। আপনি সঠিক যে C ++ 03 C90 কে বোঝায়, এবং C90 অনুমোদিত সংখ্যার উপস্থাপনা সম্পর্কে অস্পষ্ট, তবে C99 পরিবর্তন (কমপক্ষে <limits.h>সি ++ 11 এর মাধ্যমে উত্তরাধিকার সূত্রে প্রাপ্ত , আশা করি আরও সহজ সরল উপায়েও) সীমাবদ্ধ রাখতে এই তিনটিই একটি যা বিদ্যমান অনুশীলনকে কোডিং করেছিল: অন্য কোনও বাস্তবায়ন ছিল না।

আমি একমত যে INT_MINইত্যাদির অর্থ সি থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হয়েছে তবে এর অর্থ এই নয় যে মানগুলি হয়। (প্রকৃতপক্ষে, তারা কীভাবে পারে, যেহেতু প্রতিটি বাস্তবায়ন আলাদা হয়?) আপনার অনুমান যা INT_MIN1 এর মধ্যে রয়েছে -INT_MAXতা কোনও শব্দের উপর নির্ভর করে যা কেবল কোনও সি ++ স্পকে উপস্থিত হয় না। সুতরাং যখন সি ++ ম্যাক্রোগুলির অর্থগত অর্থ পেয়েছে, তবে অনুমিতি আপনার অনুমানকে সমর্থন করে এমন শব্দটি সরবরাহ করে না (বা উত্তরাধিকার সূত্রে)। এটি সি ++ টিপিতে একটি তদারকি বলে মনে হচ্ছে যা সম্পূর্ণরূপে কার্যকর দক্ষ স্বাক্ষরযুক্ত-থেকে-স্বাক্ষরিত কাস্টকে বাধা দেয়।
নিমো

@ নেমো যদি আপনি (সম্ভবত সঠিকভাবে) দাবি করেন যে সি ++ অন্য উপস্থাপনার অনুমতি দেয়, তবে এ জাতীয় বাস্তবায়ন করার সময়, আমি দাবি করি যে প্রকারের ন্যূনতম উপস্থাপনযোগ্য মান হওয়া দরকার INT_MIN নাint , কারণ যতদূর সি সম্পর্কিত, যদি টাইপটি না করে তবে এর প্রয়োজনীয়তার সাথে মেলে int, সি স্ট্যান্ডার্ড সম্ভবত কোনওভাবেই সেই বাস্তবায়নটি কভার করতে পারে না এবং সি ++ স্ট্যান্ডার্ড "সি স্ট্যান্ডার্ড কী বলে" ব্যতীত এর কোনও সংজ্ঞা দেয় না। আরও সরল ব্যাখ্যা আছে কিনা তা আমি খতিয়ে দেখব।

7
এটি চমত্কার। এই সময়ে আমি এই প্রশ্নটি কীভাবে মিস করেছি তার কোনও ধারণা নেই।
অরবিট 'ই

17

এই কোডটি কেবল আচরণের উপর নির্ভর করে, যা বর্ণনার দ্বারা বাধ্যতামূলক, সুতরাং প্রয়োজনীয়তা (ক) সহজেই সন্তুষ্ট:

int unsigned_to_signed(unsigned n)
{
  int result = INT_MAX;

  if (n > INT_MAX && n < INT_MIN)
    throw runtime_error("no signed int for this number");

  for (unsigned i = INT_MAX; i != n; --i)
    --result;

  return result;
}

এটি প্রয়োজনীয়তার সাথে এতটা সহজ নয় (খ)। এটি gcc 4.6.3 (-Os, -O2, -O3) এবং ঝনঝন 3.0 (-Os, -O, -O2, -O3) সহ একটি নো-অপারেটে সংকলন করে। ইন্টেল 12.1.0 এটি অনুকূলিত করতে অস্বীকার করে। এবং ভিজ্যুয়াল সি সম্পর্কে আমার কোনও তথ্য নেই


4
ঠিক আছে, এটি দুর্দান্ত। আমি আশা করি আমি অনুগ্রহটি ৮০:২০ বিভক্ত করতে পারি ... আমার সন্দেহ হয় যে সংকলকের যুক্তিটি চলে: যদি লুপটি বন্ধ না হয়, resultউপচে পড়ে; পূর্ণসংখ্যা ওভারফ্লো অপরিশোধিত; অতএব লুপটি সমাপ্ত হয়; সুতরাং i == nসমাপ্তির সময়; সুতরাং resultসমান n। আমাকে এখনও এইচডিডি এর উত্তর পছন্দ করতে হবে (কম স্মার্ট সংকলকগুলিতে অ প্যাথলজিকাল আচরণের জন্য) তবে এটি আরও বেশি ভোটের দাবিদার।
নিমো

4
স্বাক্ষরযুক্ত মোডিউল হিসাবে সংজ্ঞায়িত করা হয়। লুপটিও সমাপ্তির গ্যারান্টিযুক্ত কারণ nকিছু স্বাক্ষরিত মান এবং iঅবশেষে প্রতিটি স্বাক্ষরিত মান পর্যন্ত পৌঁছাতে হবে।
idupree

7

মূল উত্তরটি কেবল unsigned=> এর জন্য সমস্যার সমাধান করেছেint । যদি আমরা এর সাথে সম্পর্কিত স্বাক্ষরিত ধরণের "কিছু স্বাক্ষরবিহীন টাইপ" এর সাধারণ সমস্যাটি সমাধান করতে চাই তবে কী হবে? তদুপরি, মূল উত্তরটি স্ট্যান্ডার্ডের অংশগুলি উদ্ধৃত করে এবং কয়েকটি কোণার বিশ্লেষণে দুর্দান্ত ছিল তবে এটি কেন কাজ করেছে তা অনুভূতি পেতে সত্যিই আমাকে সহায়তা করেনি, সুতরাং এই উত্তরটি একটি দৃ concept় ধারণামূলক ভিত্তি দেওয়ার চেষ্টা করবে। এই উত্তরটি "কেন" ব্যাখ্যা করার জন্য এবং কোডটি সরল করার জন্য আধুনিক সি ++ বৈশিষ্ট্যগুলি ব্যবহার করার চেষ্টা করবে।

সি ++ 20 উত্তর

সমস্যাটি P0907 এর সাথে নাটকীয়ভাবে সহজ হয়েছে : স্বাক্ষরিত পূর্ণসংখ্যাগুলি দুটি এর পরিপূরক এবং চূড়ান্ত শব্দটি পি 1236 যা সি ++ 20 স্ট্যান্ডার্ডে ভোট হয়েছিল। এখন, উত্তরটি যতটা সম্ভব সহজ:

template<std::unsigned_integral T>
constexpr auto cast_to_signed_integer(T const value) {
    return static_cast<std::make_signed_t<T>>(value);
}

এটাই. এ static_cast(বা সি-স্টাইলের castালাই) শেষ পর্যন্ত আপনার এই প্রশ্নের জন্য আপনার প্রয়োজনীয় জিনিসটি করার গ্যারান্টিযুক্ত এবং অনেক প্রোগ্রামার যে জিনিসটি সর্বদা এটি বলে মনে করেছিল।

সি ++ 17 উত্তর

সি ++ 17 এ জিনিসগুলি আরও জটিল। আমাদের তিনটি সম্ভাব্য পূর্ণসংখ্যার উপস্থাপনা (দু'জনের পরিপূরক, একের পরিপূরক এবং সাইন-প্রস্থতা) নিয়ে কাজ করতে হবে। এমনকি আমরা যে ক্ষেত্রে জানি এটি অবশ্যই দুটিটির পরিপূরক হতে পারে কারণ আমরা সম্ভাব্য মানগুলির ব্যাপ্তিটি পরীক্ষা করেছি, স্বাক্ষরিত পূর্ণসংখ্যার সীমাটির বাইরে একটি মান রূপান্তরকরণ এখনও আমাদের একটি বাস্তবায়ন-সংজ্ঞায়িত ফলাফল দেয়। আমরা অন্যান্য উত্তরে দেখেছি এমন কৌশলগুলি ব্যবহার করতে হবে।

প্রথমত, কীভাবে সমস্যাটিকে সাধারণভাবে সমাধান করা যায় তার কোড এখানে:

template<typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
constexpr auto cast_to_signed_integer(T const value) {
    using result = std::make_signed_t<T>;
    using result_limits = std::numeric_limits<result>;
    if constexpr (result_limits::min() + 1 != -result_limits::max()) {
        if (value == static_cast<T>(result_limits::max()) + 1) {
            throw std::runtime_error("Cannot convert the maximum possible unsigned to a signed value on this system");
        }
    }
    if (value <= result_limits::max()) {
        return static_cast<result>(value);
    } else {
        using promoted_unsigned = std::conditional_t<sizeof(T) <= sizeof(unsigned), unsigned, T>;
        using promoted_signed = std::make_signed_t<promoted_unsigned>;
        constexpr auto shift_by_window = [](auto x) {
            // static_cast to avoid conversion warning
            return x - static_cast<decltype(x)>(result_limits::max()) - 1;
        };
        return static_cast<result>(
            shift_by_window( // shift values from common range to negative range
                static_cast<promoted_signed>(
                    shift_by_window( // shift large values into common range
                        static_cast<promoted_unsigned>(value) // cast to avoid promotion to int
                    )
                )
            )
        );
    }
}

স্বীকৃত উত্তরের চেয়ে এটিতে আরও কয়েকটি কাস্ট রয়েছে এবং এটি হ'ল আপনার সংকলক থেকে স্বাক্ষরিত / স্বাক্ষরবিহীন অমিল সতর্কতাগুলি নেই এবং সঠিকভাবে পূর্ণসংখ্যা প্রচারের নিয়মগুলি পরিচালনা করতে হবে তা নিশ্চিত করা।

আমাদের প্রথমে এমন দুটি সিস্টেমের ক্ষেত্রে একটি বিশেষ কেস রয়েছে যা দুটির পরিপূরক নয় (এবং সুতরাং আমাদের সর্বোচ্চ সম্ভাব্য মানটি বিশেষত হ্যান্ডেল করতে হবে কারণ এতে মানচিত্রের কিছু নেই)। এর পরে, আমরা আসল অ্যালগরিদম এ চলে যাই।

দ্বিতীয় শীর্ষ-স্তরের শর্ত সোজা: আমরা জানি মানটি সর্বাধিক মানের চেয়ে কম বা সমান, তাই এটি ফলাফলের ধরণে ফিট করে। তৃতীয় শর্তটি মন্তব্যগুলি সহ আরও কিছুটা জটিল, সুতরাং কয়েকটি বিবরণ সম্ভবত প্রতিটি বিবৃতি কেন প্রয়োজনীয় তা বুঝতে সাহায্য করবে।

ধারণাগত ভিত্তি: সংখ্যা রেখা

প্রথমত, এই windowধারণাটি কী? নিম্নলিখিত নম্বর লাইন বিবেচনা করুন:

   |   signed   |
<.........................>
          |  unsigned  |

দেখা যাচ্ছে যে দুটি সংখ্যক পরিপূরক পূর্ণসংখ্যার জন্য, আপনি সংখ্যা রেখার উপসেটটি ভাগ করতে পারেন যা উভয় প্রকার দ্বারা সমান আকারের বিভাগগুলিতে ভাগ করা যায়:

- => signed only
= => both
+ => unsigned only

<..-------=======+++++++..>

প্রতিনিধিত্ব বিবেচনা করে এটি সহজে প্রমাণ করা যায়। একটি স্বাক্ষরযুক্ত পূর্ণসংখ্যার শুরু হয় 0এবং 2 এর শক্তিতে মান বাড়ানোর জন্য সমস্ত বিট ব্যবহার করে একটি স্বাক্ষরকৃত পূর্ণসংখ্যা চিহ্ন বিট ব্যতীত সমস্ত বিটগুলির জন্য হুবহু সমান, যা এর -(2^position)পরিবর্তে মূল্যবান 2^position। এর অর্থ হল যে সমস্ত n - 1বিটের জন্য তারা একই মান উপস্থাপন করে। তারপরে, স্বাক্ষরবিহীন পূর্ণসংখ্যার আরও একটি সাধারণ বিট থাকে যা মোট মানগুলির দ্বিগুণ করে (অন্য কথায়, এটি বিট সেট ছাড়া ঠিক তেমন মান রয়েছে)। একই যুক্তি স্বাক্ষরিত পূর্ণসংখ্যার জন্য ধারন করে, বিট সেট সহ সমস্ত মান negativeণাত্মক নয় except

অন্য দুটি আইনী পূর্ণসংখ্যার উপস্থাপনা, যার পরিপূরক এবং সাইন-প্রস্থ, সমস্ত দুটি এর পরিপূরক পূর্ণসংখ্যা হিসাবে একই মানগুলি বাদ দেয়: সবচেয়ে নেতিবাচক মান। সি reinterpret_cast(+ std::bit_cast) বিট উপস্থাপনার ক্ষেত্রে নয়, উপস্থাপনযোগ্য মানগুলির পরিসীমা অনুসারে (এবং সি ++ ২০ ) বাদে পূর্ণসংখ্যার প্রকার সম্পর্কে সমস্ত কিছু সংজ্ঞায়িত করে । এর অর্থ হ'ল আমাদের বিশ্লেষণ এই তিনটি উপস্থাপকের প্রত্যেককে ধরে রাখবে যতক্ষণ না আমরা কখনও ফাঁদ উপস্থাপনা তৈরির চেষ্টা করি না। স্বাক্ষরযুক্ত স্বাক্ষরিত মানটি যা এই নিখোঁজ মানকে মানচিত্র করবে এটি একটি বরং দুর্ভাগ্যজনক: স্বাক্ষরযুক্ত স্বাক্ষরিত মানগুলির মধ্যবর্তী এক ডানদিকে। ভাগ্যক্রমে, আমাদের প্রথম শর্তটি পরীক্ষা করে (সংকলনের সময়) এমন উপস্থাপনা উপস্থিত রয়েছে কিনা এবং তারপরে এটি রানটাইম চেক সহ বিশেষভাবে পরিচালনা করে।

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

এখন, UINT_MAX + 1প্রশ্নটিতে অনুরোধ অনুসারে এটি কি আমাদের একটি ফলাফলকে একত্রিত করে? UINT_MAX + 1এর সমান 2^n, যেখানে nমান উপস্থাপনায় বিটের সংখ্যা। আমরা আমাদের উইন্ডো আকারের জন্য যে মানটি ব্যবহার করি তার সমান 2^(n - 1)(মানগুলির ক্রমে চূড়ান্ত সূচকটি আকারের চেয়ে কম) less আমরা সেই মানটি দু'বার বিয়োগ করি যার অর্থ আমরা 2 * 2^(n - 1)সমান যা সমান 2^nxগাণিতিক মোডে যোগ করা এবং বিয়োগ করা কোনও বিকল্প নয় x, তাই আমরা মূল মান মোডকে প্রভাবিত করি না 2^n

পূর্ণসংখ্যা প্রচারগুলি সঠিকভাবে পরিচালনা করছে

কারণ এটি একটি জেনেরিক ফাংশন এবং কেবল intএবং নয় unsigned, আমাদেরও অবিচ্ছেদ্য প্রচারের বিধিগুলির সাথে নিজেকে উদ্বেগ করতে হবে। দুটি আকর্ষণীয় কেস রয়েছে: একটিতে এর shortচেয়ে ছোট intএবং একটিতে এর shortআকার একই int

উদাহরণ: এর shortচেয়ে ছোটint

যদি (আধুনিক প্ল্যাটফর্মগুলিতে প্রচলিত) এর shortচেয়ে ছোট হয় intতবে আমরা এটিও জানি যে এটি কোনও unsigned shortমাপসই করা যায় int, যার অর্থ এটির যে কোনও ক্রিয়াকলাপটি আসলে ঘটবে int, তাই আমরা এটিকে এড়াতে স্পষ্টভাবে প্রচারিত প্রকারে কাস্ট করি। আমাদের চূড়ান্ত বিবৃতিটি বেশ বিমূর্ত এবং আমরা যদি সত্যিকারের মূল্যবোধগুলিকে প্রতিস্থাপন করি তবে তা বোঝা সহজ হয়। আমাদের প্রথম আকর্ষণীয় ক্ষেত্রে, সাধারণতার কোনও ক্ষতি ছাড়াই আসুন আমরা একটি 16-বিট shortএবং 17-বিট বিবেচনা করি int(যা এখনও নতুন নিয়মের অধীনে অনুমোদিত, এবং কেবলমাত্র এই দুটি পূর্ণসংখ্যার ধরণের মধ্যে কমপক্ষে একটিতে কিছু প্যাডিং বিট রয়েছে ):

constexpr auto shift_by_window = [](auto x) {
    return x - static_cast<decltype(x)>(32767) - 1;
};
return static_cast<int16_t>(
    shift_by_window(
        static_cast<int17_t>(
            shift_by_window(
                static_cast<uint17_t>(value)
            )
        )
    )
);

সর্বাধিক সম্ভব 16-বিট স্বাক্ষরিত মানের জন্য সমাধান করা

constexpr auto shift_by_window = [](auto x) {
    return x - static_cast<decltype(x)>(32767) - 1;
};
return int16_t(
    shift_by_window(
        int17_t(
            shift_by_window(
                uint17_t(65535)
            )
        )
    )
);

সরল করে

return int16_t(
    int17_t(
        uint17_t(65535) - uint17_t(32767) - 1
    ) -
    int17_t(32767) -
    1
);

সরল করে

return int16_t(
    int17_t(uint17_t(32767)) -
    int17_t(32767) -
    1
);

সরল করে

return int16_t(
    int17_t(32767) -
    int17_t(32767) -
    1
);

সরল করে

return int16_t(-1);

আমরা সবচেয়ে বড় সম্ভাব্য স্বাক্ষরযুক্ত রেখেছি এবং ফিরে পেতে -1, সাফল্য!

উদাহরণ: shortহিসাবে একই আকারint

যদি (আধুনিক প্ল্যাটফর্মগুলিতে অস্বাভাবিক) shortএকই আকার হয় intতবে অবিচ্ছেদ্য প্রচারের নিয়মটি কিছুটা আলাদা। এই ক্ষেত্রে, shortপদোন্নতি দেয় intএবং unsigned shortপ্রচার করে unsigned। সৌভাগ্যক্রমে, আমরা গণনাটি করতে চাইলে প্রতিটি ফলাফল স্পষ্টতই নিক্ষেপ করি, তাই আমরা কোনও সমস্যাযুক্ত প্রচার ছাড়াই শেষ করি। সাধারণতার কোনও ক্ষতি না করে আসুন আমরা একটি 16-বিট shortএবং 16-বিট বিবেচনা করি int:

constexpr auto shift_by_window = [](auto x) {
    return x - static_cast<decltype(x)>(32767) - 1;
};
return static_cast<int16_t>(
    shift_by_window(
        static_cast<int16_t>(
            shift_by_window(
                static_cast<uint16_t>(value)
            )
        )
    )
);

সর্বাধিক সম্ভব 16-বিট স্বাক্ষরিত মানের জন্য সমাধান করা

auto x = int16_t(
    uint16_t(65535) - uint16_t(32767) - 1
);
return int16_t(
    x - int16_t(32767) - 1
);

সরল করে

return int16_t(
    int16_t(32767) - int16_t(32767) - 1
);

সরল করে

return int16_t(-1);

আমরা সবচেয়ে বড় সম্ভাব্য স্বাক্ষরযুক্ত রেখেছি এবং ফিরে পেতে -1, সাফল্য!

আমি যদি মূল প্রশ্নের মতো কেবল সতর্কতাগুলি সম্পর্কে যত্নবান না হই intএবং কী করি unsigned?

constexpr int cast_to_signed_integer(unsigned const value) {
    using result_limits = std::numeric_limits<int>;
    if constexpr (result_limits::min() + 1 != -result_limits::max()) {
        if (value == static_cast<unsigned>(result_limits::max()) + 1) {
            throw std::runtime_error("Cannot convert the maximum possible unsigned to a signed value on this system");
        }
    }
    if (value <= result_limits::max()) {
        return static_cast<int>(value);
    } else {
        constexpr int window = result_limits::min();
        return static_cast<int>(value + window) + window;
    }
}

এটি সরাসরি দেখুন

https://godbolt.org/z/74hY81

এখানে আমরা দেখতে যে ঝনঝন, জিসিসি, এবং আইসিসি জন্য কোন কোড জেনারেট castএবং cast_to_signed_integer_basic-O2এবং -O3ও MSVC কোন কোড জেনারেট করে /O2তাই সমাধান অনুকূল হয়।


3

আপনি যা করতে চান তা আপনি স্পষ্টভাবে সংকলককে বলতে পারেন:

int unsigned_to_signed(unsigned n) {
  if (n > INT_MAX) {
    if (n <= UINT_MAX + INT_MIN) {
      throw "no result";
    }
    return static_cast<int>(n + INT_MIN) - (UINT_MAX + INT_MIN + 1);
  } else {
    return static_cast<int>(n);
  }
}

( ) থেকে gcc 4.7.2জন্য সংকলনx86_64-linuxg++ -O -S test.cpp

_Z18unsigned_to_signedj:
    movl    %edi, %eax
    ret

UINT_MAXএটি টাইপের একটি অভিব্যক্তি unsigned intএবং এটি আপনার পুরো static_cast<int>(n + INT_MIN) - (UINT_MAX + INT_MIN + 1)ধরণের করে তোলে । এটি ঠিক করা সম্ভব হবে, যদিও, এবং আমি এটি এখনও একই সংকলন করা আশা করি।

2

যদি xআমাদের ইনপুট হয় ...

যদি x > INT_MAX, আমরা একটি ধ্রুবক kএটি 0<< x - k*INT_MAX> সন্ধান করতে চাই INT_MAX

এটি সহজ - unsigned int k = x / INT_MAX;। তারপরে, যাকunsigned int x2 = x - k*INT_MAX;

আমরা এখন নিরাপদে কাস্ট x2করতে পারি int। দিনint x3 = static_cast<int>(x2);

আমরা এখন UINT_MAX - k * INT_MAX + 1থেকে x3, এর মতো কিছু বিয়োগ করতে চাই k > 0

এখন, 2s পরিপূরক সিস্টেমে, এত দিন x > INT_MAX, এটি কাজ করে:

unsigned int k = x / INT_MAX;
x -= k*INT_MAX;
int r = int(x);
r += k*INT_MAX;
r -= UINT_MAX+1;

নোট যে UINT_MAX+1সি ++ এর গ্যারান্টিযুক্ত শূন্য, ইনট এ রূপান্তরটি একটি নূপুর ছিল এবং আমরা k*INT_MAXএটির বিয়োগ করে আবার "একই মান" এ যুক্ত করেছিলাম। সুতরাং একটি গ্রহণযোগ্য অপ্টিমাইজারের সেই সমস্ত টমফুলারি মুছতে সক্ষম হওয়া উচিত!

যে সমস্যা x > INT_MAXবা না ছেড়ে দেয় । ঠিক আছে, আমরা 2 টি শাখা তৈরি করি যার একটি রয়েছে x > INT_MAXএবং একটি ছাড়াই। এক ছাড়া একটি স্ট্রেইট কাস্ট করে, যা সংকলক একটি নূরে অনুকূলিত করে। অপ্টিমাইজারটি শেষ হওয়ার পরে ... স্মার্ট অপ্টিমাইজার উভয় শাখাকে একই জিনিস হিসাবে উপলব্ধি করে এবং শাখাটি ফেলে দেয়।

সমস্যাগুলি: যদি UINT_MAXসত্যিই তুলনামূলকভাবে বড় হয় তবে উপরেরগুলি INT_MAXকাজ নাও করতে পারে। আমি k*INT_MAX <= UINT_MAX+1নিখুঁতভাবে ধরে নিচ্ছি ।

আমরা সম্ভবত কিছু এনাম দিয়ে এটি আক্রমণ করতে পারি:

enum { divisor = UINT_MAX/INT_MAX, remainder = UINT_MAX-divisor*INT_MAX };

আমি বিশ্বাস করি এমন 2s পরিপূরক সিস্টেমে যা 2 এবং 1 এর সাথে কাজ করে (আমরা কি সেই গণিতের কাজ করার গ্যারান্টিযুক্ত? এটি মুশকিল ...), এবং এগুলি ভিত্তিক যুক্তিযুক্ত যা সহজেই নন-2 এস পরিপূরক সিস্টেমগুলিকে অপ্টিমাইজ করে ...

এটি ব্যতিক্রম ক্ষেত্রেও খোলে। এটি কেবল তখনই সম্ভব যখন UINT_MAX (INT_MIN-INT_MAX) এর চেয়ে অনেক বেশি বড় হয়, তাই আপনি যদি কোনওভাবে সেই প্রশ্নটি জিজ্ঞাসা করে তবে আপনার ব্যতিক্রম কোডটি একটি ব্লকে রেখে দিতে পারেন, এবং এটি আপনাকে কোনও traditionalতিহ্যবাহী সিস্টেমে ধীর করবে না।

এর সাথে সঠিকভাবে ডিল করার জন্য কীভাবে এই সংকলন-সময় ধ্রুবকগুলি তৈরি করবেন তা আমি ঠিক নিশ্চিত নই।


UINT_MAXএর সাথে তুলনামূলকভাবে ছোট হতে পারে না INT_MAX, কারণ স্পেকটি গ্যারান্টি দেয় যে প্রতিটি ইতিবাচক স্বাক্ষরিত ইন্ট একটি স্বাক্ষরবিহীন ইন্ট হিসাবে প্রতিনিধিত্বযোগ্য। তবে UINT_MAX+1প্রতিটি সিস্টেমে শূন্য; স্বাক্ষরবিহীন গাণিতিক সর্বদা মডুলো UINT_MAX+1। তবুও এখানে একটি কার্যক্ষম পদ্ধতির কার্নেল থাকতে পারে ...
নিমো

@ নেমো এই থ্রেডটি অনুসরণ করছেন, সুতরাং আমার সম্ভাব্য সুস্পষ্ট প্রশ্নটিকে ক্ষমা করুন: আপনার বক্তব্যটি কি UINT_MAX+1'03-স্পেস্ক-এ প্রতিষ্ঠিত প্রতিটি সিস্টেমে শূন্য? যদি তাই হয় তবে আমার কোনও নির্দিষ্ট অনুচ্ছেদ রয়েছে কি? ধন্যবাদ
হুজক্রাইগ

@ হোজক্রেইগ: বিভাগ 3.9.1 অনুচ্ছেদ 4: "স্বাক্ষরযুক্ত স্বাক্ষরযুক্ত স্বাক্ষরিত স্বাক্ষরবিহীন পূর্ণসংখ্যাগুলি 2 ^ n পাটিগণিতের মডুলো 2 ^ n এর আইন মেনে চলবে যেখানে n নির্দিষ্ট পরিমাণের পূর্ণসংখ্যার মান উপস্থাপনের ক্ষেত্রে বিটের সংখ্যা", একটি পাদটীকা বলে "এর থেকে বোঝা যায় যে স্বাক্ষরবিহীন গাণিতিকগুলি ওভারফ্লো হয় না কারণ ফলাফল স্বাক্ষরিত পূর্ণসংখ্যার ধরণের দ্বারা প্রতিনিধিত্ব করা যায় না এমন ফলাফলটি মোডুলোতে হ্রাস করা হয় যা সবচেয়ে বড় মানের চেয়ে বড় যা ফলাফল স্বাক্ষরিত পূর্ণসংখ্যার ধরণের দ্বারা প্রতিনিধিত্ব করা যায়" " মূলত স্বাক্ষরযুক্ত আপনি যেভাবে চান / প্রত্যাশায় কাজ করতে নির্দিষ্ট করা হয়।
নিমো

@ নিমো ধন্যবাদ খুব বেশি প্রশংশিত.
WhozCraig

1

std::numeric_limits<int>::is_moduloএকটি সংকলন সময় ধ্রুবক। যাতে আপনি এটি টেমপ্লেট বিশেষায়নের জন্য ব্যবহার করতে পারেন। সমস্যা সমাধান হয়েছে, কমপক্ষে যদি সংকলক ইনলাইনিংয়ের সাথে খেলেন।

#include <limits>
#include <stdexcept>
#include <string>

#ifdef TESTING_SF
    bool const testing_sf = true;
#else
    bool const testing_sf = false;
#endif

// C++ "extensions"
namespace cppx {
    using std::runtime_error;
    using std::string;

    inline bool hopefully( bool const c ) { return c; }
    inline bool throw_x( string const& s ) { throw runtime_error( s ); }

}  // namespace cppx

// C++ "portability perversions"
namespace cppp {
    using cppx::hopefully;
    using cppx::throw_x;
    using std::numeric_limits;

    namespace detail {
        template< bool isTwosComplement >
        int signed_from( unsigned const n )
        {
            if( n <= unsigned( numeric_limits<int>::max() ) )
            {
                return static_cast<int>( n );
            }

            unsigned const u_max = unsigned( -1 );
            unsigned const u_half = u_max/2 + 1;

            if( n == u_half )
            {
                throw_x( "signed_from: unsupported value (negative max)" );
            }

            int const i_quarter = static_cast<int>( u_half/2 );
            int const int_n1 = static_cast<int>( n - u_half );
            int const int_n2 = int_n1 - i_quarter;
            int const int_n3 = int_n2 - i_quarter;

            hopefully( n == static_cast<unsigned>( int_n3 ) )
                || throw_x( "signed_from: range error" );

            return int_n3;
        }

        template<>
        inline int signed_from<true>( unsigned const n )
        {
            return static_cast<int>( n );
        }
    }    // namespace detail

    inline int signed_from( unsigned const n )
    {
        bool const is_modulo = numeric_limits< int >::is_modulo;
        return detail::signed_from< is_modulo && !testing_sf >( n );
    }
}    // namespace cppp

#include <iostream>
using namespace std;
int main()
{
    int const x = cppp::signed_from( -42u );
    wcout << x << endl;
}


সম্পাদনা : নন-মডিউলার-ইন মেশিনগুলিতে সম্ভাব্য ফাঁদ এড়াতে ফিক্সড কোড (একমাত্র বিদ্যমান বলে জানা যায়, যিনি ইউসিস ক্লিয়ারপথের প্রত্নতাত্ত্বিকভাবে কনফিগার করা সংস্করণ)। সরলতার জন্য এটি -2 এন -1 মান সমর্থন না করেই করা হয় যেখানে এনint যেমন মেশিনে (যেমন ক্লিয়ারপথে) মান বিটের সংখ্যা is অনুশীলনে এই মানটি মেশিন দ্বারা সমর্থিত হবে না (অর্থাত্, সাইন-ও-প্রস্থ বা 1 এর পরিপূর্ণ প্রতিনিধিত্ব সহ)।


1

আমি মনে করি ইনট টাইপটি কমপক্ষে দুটি বাইট, সুতরাং INT_MIN এবং INT_MAX বিভিন্ন প্ল্যাটফর্মে পরিবর্তিত হতে পারে।

মৌলিক প্রকারের

শিরোনাম


ডিফল্ট হিসাবে "-মিন্ট 8" দিয়ে কনফিগার করা 6809 এর জন্য একটি সংকলক ব্যবহার করার জন্য আমি অভিশপ্ত, যেখানে int 8 বিট :-( (এটি ভেক্টরেক্সের বিকাশের পরিবেশ) দীর্ঘ 2 বাইট, দীর্ঘ দীর্ঘ 4 বাইট এবং কি সংক্ষিপ্ত তা আমার কোনও ধারণা নেই ...
গ্রাহাম তোল

1

আমার অর্থ মেমকি ব্যবহার করা হচ্ছে। যে কোনও শালীন সংকলক এটিকে অপ্টিমাইজ করতে জানে:

#include <stdio.h>
#include <memory.h>
#include <limits.h>

static inline int unsigned_to_signed(unsigned n)
{
    int result;
    memcpy( &result, &n, sizeof(result));
    return result;
}

int main(int argc, const char * argv[])
{
    unsigned int x = UINT_MAX - 1;
    int xx = unsigned_to_signed(x);
    return xx;
}

আমার জন্য (এক্সকোড 8.3.2, অ্যাপল এলএলভিএম 8.1, -O3), যা উত্পাদন করে:

_main:                                  ## @main
Lfunc_begin0:
    .loc    1 21 0                  ## /Users/Someone/main.c:21:0
    .cfi_startproc
## BB#0:
    pushq    %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    ##DEBUG_VALUE: main:argc <- %EDI
    ##DEBUG_VALUE: main:argv <- %RSI
Ltmp3:
    ##DEBUG_VALUE: main:x <- 2147483646
    ##DEBUG_VALUE: main:xx <- 2147483646
    .loc    1 24 5 prologue_end     ## /Users/Someone/main.c:24:5
    movl    $-2, %eax
    popq    %rbp
    retq
Ltmp4:
Lfunc_end0:
    .cfi_endproc

4
এই প্রশ্নের উত্তর নেই হিসাবে একটি স্বাক্ষরবিহীন বাইনারি উপস্থাপনা করা হয় না মান দ্বারা নিশ্চিত স্বাক্ষরিত উপস্থাপনা মেলে।
TLW
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.