(A - b <0) এবং যদি (a <b) এর মধ্যে পার্থক্য


252

আমি জাভার ArrayListউত্স কোডটি পড়ছিলাম এবং if-বিবৃতিতে কিছু তুলনা লক্ষ্য করলাম।

জাভা 7-তে, পদ্ধতিটি grow(int)ব্যবহার করে

if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;

জাভা 6 এ growউপস্থিত ছিল না। পদ্ধতিটি ensureCapacity(int)যদিও ব্যবহার করে

if (newCapacity < minCapacity)
    newCapacity = minCapacity;

পরিবর্তনের পিছনে কারণ কী ছিল? এটি একটি পারফরম্যান্স ইস্যু ছিল বা কেবল একটি স্টাইল?

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


35
@ তুনাকি ওভারফ্লো প্রতিরোধের ক্ষেত্রে কীভাবে if (newCapacity - minCapacity < 0)ভাল if (newCapacity < minCapacity)?
ইরান

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

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

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

উত্তর:


285

a < bএবং a - b < 0দুটি ভিন্ন জিনিস বোঝাতে পারে। নিম্নলিখিত কোড বিবেচনা করুন:

int a = Integer.MAX_VALUE;
int b = Integer.MIN_VALUE;
if (a < b) {
    System.out.println("a < b");
}
if (a - b < 0) {
    System.out.println("a - b < 0");
}

যখন চালানো হবে, এটি কেবল মুদ্রণ করবে a - b < 0। যা ঘটে তা a < bস্পষ্টতই মিথ্যা, তবে a - bউপচে পড়ে এবং হয়ে যায় -1, যা নেতিবাচক।

এখন, এই কথাটি বলার পরে, বিবেচনা করুন যে অ্যারের একটি দৈর্ঘ্য রয়েছে যা সত্যই নিকটে Integer.MAX_VALUE। কোডটি ArrayListএইভাবে চলে:

int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);

oldCapacityসত্যই Integer.MAX_VALUEতাই এর কাছাকাছি newCapacity(যা হয় oldCapacity + 0.5 * oldCapacity) উপচে Integer.MIN_VALUEপড়বে এবং হয়ে উঠবে (অর্থাৎ নেতিবাচক)। তারপরে, minCapacity পাতালগুলি বিয়োগ করে একটি ইতিবাচক সংখ্যায় ফিরে আসে back

এই চেকটি নিশ্চিত করে যে এটি ifকার্যকর করা হয়নি। কোডটি যদি লিখিত হয় তবে if (newCapacity < minCapacity)এটি trueএই ক্ষেত্রে (যেহেতু newCapacityনেতিবাচক) তাই এটি নির্বিশেষে newCapacityবাধ্য হতে বাধ্য হবে ।minCapacityoldCapacity

এই ওভারফ্লো কেসটি যদি পরবর্তী দ্বারা পরিচালিত হয়। যখন newCapacityউপচে পড়েছে, এটি হবে true: MAX_ARRAY_SIZEহিসাবে সংজ্ঞায়িত করা হয় Integer.MAX_VALUE - 8এবং Integer.MIN_VALUE - (Integer.MAX_VALUE - 8) > 0হয় truenewCapacityঅতএব ন্যায়ত পরিচালিত হয়: hugeCapacityপদ্ধতি আয় MAX_ARRAY_SIZEবা Integer.MAX_VALUE

এনবি: এই // overflow-conscious codeপদ্ধতিতে এই মন্তব্যটি বলছে।


8
গণিত এবং সিএসের মধ্যে পার্থক্যের জন্য ভাল ডেমো
piggybox

36
@ পিগজিবক্স আমি এটি বলব না। এটি গণিত। এটি কেবল জেডে গণিত নয়, তবে পূর্ণসংখ্যার মডুলোর 2 ^ 32 সংস্করণে (সাধারণভাবে উপস্থাপনাগুলি স্বাভাবিকের চেয়ে আলাদাভাবে বেছে নেওয়া হয়েছে)। এটি একটি সঠিক গাণিতিক সিস্টেম, কেবল "লোল কম্পিউটার এবং তাদের কীর্তি" নয়।
হরোল

2
আমি এমন কোড লিখেছি যা একেবারে উপচে পড়েনি।
আলেকসান্ডার ডাবিনস্কি

আইআইআরসি প্রসেসরগুলি স্বাক্ষরিত পূর্ণসংখ্যার a - bউপরের চেয়ে কম নির্দেশ প্রয়োগ করে এবং শীর্ষস্থানীয় বিটটি একটি কিনা তা যাচাই করে 1। তারা কীভাবে ওভারফ্লো পরিচালনা করে?
বেন লেগিগেরো

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

105

আমি এই ব্যাখ্যাটি পেয়েছি :

মঙ্গলবার, মার্চ 9, 2010 এ 03:02 এ, কেভিন এল স্টার্ন লিখেছেন:

আমি একটি তাত্ক্ষণিক অনুসন্ধান করেছি এবং এটি প্রদর্শিত হচ্ছে যে জাভা প্রকৃতপক্ষে দু'জনের পরিপূরক। তবুও, দয়া করে আমাকে এটি উল্লেখ করার অনুমতি দিন, সাধারণভাবে, এই ধরণের কোডটি আমাকে চিন্তিত করে যেহেতু আমি পুরোপুরি প্রত্যাশা করি যে কোনও সময় কেউ আসবেন এবং ডাইমাইট্রোর পরামর্শ মতো ঠিক করবেন; যে কেউ পরিবর্তন হবে:

if (a - b > 0)

প্রতি

if (a > b)

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

if (oldCapacity > RESIZE_OVERFLOW_THRESHOLD) {
   // Do something
} else {
  // Do something else
}

এটি একটি ভাল পয়েন্ট।

ইন ArrayListআমরা এটা করতে পারেন না (বা অন্তত compatibly নয়), কারণ ensureCapacityএকটি পাবলিক এপিআই এবং কার্যকরভাবে ইতিমধ্যে একটি ইতিবাচক ধারণক্ষমতা যে সন্তুষ্ট করা যাবে না জন্য অনুরোধ হিসাবে ঋণাত্মক সংখ্যা গ্রহণ করে।

বর্তমান এপিআই এর মতো ব্যবহৃত হয়:

int newcount = count + len;
ensureCapacity(newcount);

আপনি যদি ওভারফ্লো এড়াতে চান তবে আপনার খুব কম প্রাকৃতিক কিছুতে পরিবর্তন করতে হবে

ensureCapacity(count, len);
int newcount = count + len;

যাইহোক, আমি ওভারফ্লো-সচেতন কোড রাখছি, তবে আরও সতর্কতা মন্তব্য যুক্ত করছি, এবং "আউট-আস্তরণের" বিশাল অ্যারে তৈরি করা যাতে ArrayListকোডটি এখন দেখতে লাগে তেমন:

/**
 * Increases the capacity of this <tt>ArrayList</tt> instance, if
 * necessary, to ensure that it can hold at least the number of elements
 * specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 */
public void ensureCapacity(int minCapacity) {
    modCount++;

    // Overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

/**
 * The maximum size of array to allocate.
 * Some VMs reserve some header words in an array.
 * Attempts to allocate larger arrays may result in
 * OutOfMemoryError: Requested array size exceeds VM limit
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 */
private void grow(int minCapacity) {
    // Overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);

    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

private int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

ওয়েব্রেভ পুনরুত্থিত।

মার্টিন

জাভা In-তে, আপনি যদি এপিআই ব্যবহার করেন তবে:

int newcount = count + len;
ensureCapacity(newcount);

আর newCountউপচে (এই নেতিবাচক হয়ে), if (minCapacity > oldCapacity)মিথ্যা ফিরে যাবে এবং আপনি ভুল করে অনুমান হতে পারে যে ArrayListদ্বারা বৃদ্ধি করা হয় len


2
ভাল ধারণা কিন্তু এটি বাস্তবায়নেরensureCapacity দ্বারা দ্বন্দ্বযুক্ত ; যদি minCapacityনেতিবাচক হয় তবে আপনি কখনই সেই জায়গায় পৌঁছাতে পারবেন না — জটিল বাস্তবায়ন প্রতিরোধের ভান করার মতোই এটি চুপচাপ উপেক্ষা করা হবে। সুতরাং পাবলিক এপিআই এর সামঞ্জস্যের জন্য "আমরা এটি করতে পারি না" এটি একটি অদ্ভুত যুক্তি already এই আচরণের উপর নির্ভর করে কেবল কলকারীরা হ'ল অভ্যন্তরীণ।
হলগার

1
@ হোলজার যদি minCapacityখুব নেতিবাচক হয় (যেমন আপনি অ্যারেলিস্টের intবর্তমান আকারকে যুক্ত করতে চান এমন উপাদানগুলির সংখ্যায় যোগ minCapacity - elementData.lengthকরার সময় ওভারফ্লো হয়ে গেছে ), আবার উপচে পড়ুন এবং ইতিবাচক হয়ে উঠুন। আমি এটি বুঝতে পারি।
ইরান

1
@ হোলজার যাইহোক, তারা এটি আবার জাভা 8 এ পরিবর্তন করেছেন if (minCapacity > minExpand), যা আমি বুঝতে পারি না।
ইরান

হ্যাঁ, দুটি addAllপদ্ধতিই একমাত্র ক্ষেত্রে যেখানে এটি বর্তমান আকারের যোগফল এবং নতুন উপাদানের সংখ্যার সংখ্যার উপচে পড়তে পারে সে হিসাবে এটি প্রাসঙ্গিক। তবুও, এটি অভ্যন্তরীণ কল এবং "আমরা এটি পরিবর্তন করতে পারি না কারণ ensureCapacityএটি একটি সর্বজনীন এপিআই" যুক্তিটি একটি অদ্ভুত যুক্তি যখন বাস্তবে ensureCapacityনেতিবাচক মানগুলিকে উপেক্ষা করে না। জাভা 8 এপিআই সেই আচরণটি পরিবর্তন করে নি, ArrayListএটি প্রাথমিকভাবে যখন প্রাথমিক অবস্থায় থাকে (যেমন ডিফল্ট ক্ষমতা সহ আরম্ভ করে এখনও খালি থাকে) তখন এটি ডিফল্ট ক্ষমতার নীচে সক্ষমতা উপেক্ষা করে all
হলগার

অন্য কথায়, newcount = count + lenঅভ্যন্তরীণ ব্যবহারের ক্ষেত্রে যখন যুক্তিটি সঠিক হয় তবে এটি publicপদ্ধতিতে প্রযোজ্য না ensureCapacity()
হলগার

19

কোডটি দেখছেন:

int newCapacity = oldCapacity + (oldCapacity >> 1);

যদি oldCapacityবেশ বড় হয় তবে এটি উপচে newCapacityপড়বে এবং নেতিবাচক সংখ্যা হবে। মত একটি তুলনা newCapacity < oldCapacityইচ্ছার ভুল মূল্যায়ন trueএবং ArrayListহত্তয়া ব্যর্থ হবে।

পরিবর্তে, লিখিত হিসাবে কোডটি ( newCapacity - minCapacity < 0মিথ্যা প্রত্যাবর্তন করে) newCapacityপরবর্তী পংক্তিতে এর নেতিবাচক মানটিকে আরও মূল্যায়ন করার অনুমতি দেবে , ফলস্বরূপ ( ) newCapacityডাকে বড় হয়ে ওঠার জন্য পুনরায় গণনা করার ফলে ।hugeCapacitynewCapacity = hugeCapacity(minCapacity);ArrayListMAX_ARRAY_SIZE

// overflow-conscious codeমন্তব্যটি এটির পরিবর্তে তির্যক হলেও যোগাযোগ করার চেষ্টা করছে।

সুতরাং, নীচের অংশে, নতুন তুলনাটি ArrayListপূর্বনির্ধারিতের চেয়ে বড় বরাদ্দ করা থেকে সুরক্ষা MAX_ARRAY_SIZEদেয় যখন প্রয়োজনে সেই সীমা পর্যন্ত ডান বাড়তে দেয়।


1

দুটি রূপগুলি একইরকম আচরণ করে যতক্ষণ না অভিব্যক্তিটি a - bওভারফ্লো হয়, সেই ক্ষেত্রে তারা বিপরীত হয়। যদি aএকটি বড় নেতিবাচক হয়, এবং bএকটি বৃহত্তর ধনাত্মক হয়, তবে (a < b)এটি স্পষ্টভাবে সত্য, তবে a - bইতিবাচক হওয়ার জন্য উপচে পড়বে, তাই (a - b < 0)মিথ্যাও।

আপনি যদি x86 বিধানসভা কোডের সাথে পরিচিত হন তবে এটি (a < b)একটি দ্বারা প্রয়োগ করা হয়েছে তা বিবেচনা করুনjge , যখন এসএফ = বন্ধ থাকাকালীন যদি স্টেটমেন্টের দেহের চারদিকে শাখা থাকে। অন্যদিকে, এর (a - b < 0)মতো কাজ করবে jns, যখন শাখাগুলি যখন এসএফ = 0 থাকে তখন এইগুলি, অফ = 1 থাকাকালীন এগুলি আলাদাভাবে স্পষ্টভাবে আচরণ করে।

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