জাভা কীভাবে পূর্ণসংখ্যার আন্ডারফ্লোস এবং ওভারফ্লোগুলি পরিচালনা করে এবং আপনি এটি কীভাবে পরীক্ষা করবেন?


226

জাভা কীভাবে পূর্ণসংখ্যার আন্ডারফ্লোস এবং ওভারফ্লোগুলি পরিচালনা করে?

এর থেকে শুরু করে আপনি কীভাবে পরীক্ষা / পরীক্ষা করবেন যে এটি হচ্ছে?


28
এটি খুব খারাপ যে জাভা সিপিইউর ওভারফ্লো পতাকাটিতে পরোক্ষ অ্যাক্সেস সরবরাহ করে না , যেমন সি # তে করা হয়েছে
ড্র নোকস

@ ড্রউনোকেস এবং এটি খুব খারাপ যে checkedআমি # যতদূর জানি সি # ডিফল্ট হয় না। আমি এটি খুব বেশি ব্যবহার করে দেখছি না, এবং টাইপিং checked { code; }কোনও পদ্ধতিতে কল করার মতো কাজ।
মার্টেন বোদেউয়েস

2
@ মার্টেনবোডওয়েস, আপনি কোনও সমাবেশের সংকলনের সময় এটি ডিফল্ট হিসাবে সেট করতে পারেন। csc /checked ...বা ভিজ্যুয়াল স্টুডিওতে প্রজেক্টের সম্পত্তি প্যানেতে সম্পত্তি সেট করুন।
ড্রয় নোকস

@ ড্র্রুনোকস ঠিক আছে, আকর্ষণীয়। কিছুটা আশ্চর্যজনক যে এটি কোডের বাইরে যদিও একটি সেটিং। সাধারণভাবে আমি এই জাতীয় সেটিংস নির্বিশেষে কোনও প্রোগ্রামের একই আচরণ করতে চাই (সম্ভবত যুক্তি বাদে)।
মার্টেন বোদেউয়েস

@ মার্টেনবোডওয়েস, আমি মনে করি যুক্তিটি হ'ল চেক করার জন্য একটি তুচ্ছ তুচ্ছ ওভারহেড আছে head সুতরাং সম্ভবত আপনি এটি ডিবাগ বিল্ডগুলিতে সক্ষম করে তুলবেন, তারপরে এটি অন্যান্য ধরণের জোরের মতো মুক্তির বিল্ডগুলিতে অক্ষম করুন।
ড্রয় নোকস

উত্তর:


217

যদি এটি উপচে পড়ে তবে এটি সর্বনিম্ন মানটিতে ফিরে যায় এবং সেখান থেকে অবিরত থাকে। যদি এটি প্রবাহিত হয় তবে এটি সর্বাধিক মানটিতে ফিরে যায় এবং সেখান থেকে অবিরত থাকে।

আপনি নীচে আগে তা পরীক্ষা করে দেখতে পারেন:

public static boolean willAdditionOverflow(int left, int right) {
    if (right < 0 && right != Integer.MIN_VALUE) {
        return willSubtractionOverflow(left, -right);
    } else {
        return (~(left ^ right) & (left ^ (left + right))) < 0;
    }
}

public static boolean willSubtractionOverflow(int left, int right) {
    if (right < 0) {
        return willAdditionOverflow(left, -right);
    } else {
        return ((left ^ right) & (left ^ (left - right))) < 0;
    }
}

(আপনি একই পরীক্ষার জন্য বিকল্প intদ্বারা প্রতিস্থাপন করতে পারেন )longlong

আপনি কি মনে করেন যে, এই প্রায়ই চেয়ে বেশি ঘটতে পারে, তাহলে একটি ডাটাটাইপ বা বস্তুর বৃহত্তর মূল্যবোধ, যেমন সংরক্ষণ করতে পারেন ব্যবহারের বিষয়ে বিবেচনা longহয়তো বা java.math.BigInteger। শেষটি ওভারফ্লো হয় না, ব্যবহারিকভাবে, উপলব্ধ জেভিএম মেমরির সীমা।


আপনি যদি ইতিমধ্যে জাভা 8-এ উপস্থিত হয়ে থাকেন তবে আপনি নতুন Math#addExact()এবং Math#subtractExact()পদ্ধতিগুলি ব্যবহার করতে পারেন যা ArithmeticExceptionওভারফ্লোতে ছড়িয়ে পড়বে ।

public static boolean willAdditionOverflow(int left, int right) {
    try {
        Math.addExact(left, right);
        return false;
    } catch (ArithmeticException e) {
        return true;
    }
}

public static boolean willSubtractionOverflow(int left, int right) {
    try {
        Math.subtractExact(left, right);
        return false;
    } catch (ArithmeticException e) {
        return true;
    }
}

উত্স কোডটি যথাক্রমে এখানে এবং এখানে পাওয়া যাবে

অবশ্যই, আপনি এগুলি কেবল কোনও booleanইউটিলিটি পদ্ধতিতে লুকানোর পরিবর্তে এখুনি ব্যবহার করতে পারেন ।


13
@ ডিডব্লাহ, আসুন জাভা যে কোনও সর্বাধিক এবং ন্যূনতম মানগুলি +100, -100যথাক্রমে অনুমতি দেয় তা হ'ল । যদি আপনি একটি জাভা পূর্ণসংখ্যার সাথে একটি যুক্ত করে থাকেন তবে প্রক্রিয়াটি এটি প্রবাহিত হওয়ার সাথে সাথে দেখতে হবে। 98, 99, 100, -100, -99, -98, ...। এটি কি আরও অর্থবোধ করে?
অস্টিন এ 3

6
আমি এখনই কোডটি ব্যবহার না করে ইউটিলিটি পদ্ধতিগুলি ব্যবহার করার পরামর্শ দিচ্ছি। ইউটিলিটি পদ্ধতিগুলি অন্তর্ভুক্ত এবং মেশিন নির্দিষ্ট কোড দ্বারা প্রতিস্থাপন করা হবে। একটি দ্রুত পরীক্ষায় দেখা গেছে যে ম্যাথ.এডএক্স্যাক্ট একটি অনুলিপি করা পদ্ধতি (জাভা 1.8.0_40) এর চেয়ে 30% বেশি দ্রুত।
তিলমানজ জেড

1
জাভাদোকগুলি Math#addExactলেখার সময় @ এরিকই সাধারণত বাক্যবিন্যাস হয় - সাধারণত রূপান্তরিত হতে চাইলে Math.addExactকখনও কখনও অন্য ফর্মটি প্রায় আটকে থাকে
পোকেচু 22

1
If it underflows, it goes back to the maximum value and continues from there.- আপনার মনে হচ্ছে নেতিবাচক ওভারফ্লোতে বিভ্রান্ত হয়ে পড়েছেন under পূর্ণসংখ্যার আন্ডারফ্লো সর্বদা ঘটে (যখন ফলাফলটি ভগ্নাংশ হয়)।
নাভে

1
en.wikedia.org/wiki/Arithmetic_underflow বলেছেন যে আন্ডারফ্লো এমন একটি কম্পিউটার প্রোগ্রাম যেখানে একটি গণনার ফলাফল কম্পিউটারের তুলনায় আসলে তার সিপিইউতে স্মৃতিতে প্রতিনিধিত্ব করতে পারে তার চেয়ে অনেক ছোট পরম মান। সুতরাং জাভা ইন্টিজারে আন্ডারফ্লো প্রযোজ্য নয়। @ বালুসসি
ইয়াও

66

ঠিক আছে, আদিম পূর্ণসংখ্যার প্রকারের হিসাবে, জাভা মোটেও ওভার / আন্ডারফ্লো হ্যান্ডেল করে না (ভাসা এবং দ্বিগুণ আচরণের জন্য এটি আইআইইই-75৫4 ম্যান্ডেটের মতোই + +- অনন্ততায় চলে যাবে)।

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

public int addWithOverflowCheck(int a, int b) {
    // the cast of a is required, to make the + work with long precision,
    // if we just added (a + b) the addition would use int precision and
    // the result would be cast to long afterwards!
    long result = ((long) a) + b;
    if (result > Integer.MAX_VALUE) {
         throw new RuntimeException("Overflow occured");
    } else if (result < Integer.MIN_VALUE) {
         throw new RuntimeException("Underflow occured");
    }
    // at this point we can safely cast back to int, we checked before
    // that the value will be withing int's limits
    return (int) result;
}

নিক্ষেপ শৃঙ্খলার জায়গায় আপনি কী করবেন, তা আপনার অ্যাপ্লিকেশন প্রয়োজনীয়তার উপর নির্ভর করে (নিক্ষেপ করুন, নূন্যতম / সর্বোচ্চে ফ্লাশ করুন বা যা কিছু লগইন করুন)। যদি আপনি দীর্ঘ ক্রিয়াকলাপগুলিতে ওভারফ্লো সনাক্ত করতে চান, আপনি আদিমদের সাথে ভাগ্যের বাইরে থাকেন, পরিবর্তে BigInteger ব্যবহার করুন।


সম্পাদনা (2014-05-21): যেহেতু এই প্রশ্নটি বেশিরভাগ ঘন ঘন উল্লেখ করা হয়েছে এবং আমাকে নিজেই একই সমস্যাটি সমাধান করতে হয়েছিল, একই পদ্ধতিতে কোনও সিপিইউ তার ভি পতাকা গণনা করবে ওভারফ্লো অবস্থার মূল্যায়ন করা বেশ সহজ।

এটি মূলত একটি বুলিয়ান এক্সপ্রেশন যা উভয় অপারেন্ডের চিহ্ন পাশাপাশি ফলাফলের সাথে জড়িত:

/**
 * Add two int's with overflow detection (r = s + d)
 */
public static int add(final int s, final int d) throws ArithmeticException {
    int r = s + d;
    if (((s & d & ~r) | (~s & ~d & r)) < 0)
        throw new ArithmeticException("int overflow add(" + s + ", " + d + ")");    
    return r;
}

জাভাতে সম্পূর্ণ 32 বিটগুলিতে এক্সপ্রেশনটি (যদি হয়) প্রয়োগ করা সহজ হয় এবং <0 ব্যবহার করে ফলাফলটি পরীক্ষা করে নিন (এটি কার্যকরভাবে সাইন বিটটি পরীক্ষা করবে)। সমস্ত পূর্ণসংখ্যার আদিম ধরণের জন্য নীতিটি হুবহু একই রকম কাজ করে , উপরের পদ্ধতিতে সমস্ত ঘোষণাকে দীর্ঘ পরিবর্তন করে এটিকে দীর্ঘস্থায়ী করে তোলে।

ছোট ধরণের ক্ষেত্রে, অন্তর্নিহিত রূপান্তরিত কারণে (বিশদের জন্য বিটওয়াইজ অপারেশনের জন্য জেএলএস দেখুন) <0 পরীক্ষা না করে চেকটি স্বাক্ষর করে স্পষ্টভাবে সাইনটি বিট করতে হবে (শর্ট অপারেন্ডসের জন্য 0x8000, বাইট অপারেন্ডসের জন্য 0x80, ক্যাসট সামঞ্জস্য করুন) এবং প্যারামিটার ঘোষণা appropiately):

/**
 * Subtract two short's with overflow detection (r = d - s)
 */
public static short sub(final short d, final short s) throws ArithmeticException {
    int r = d - s;
    if ((((~s & d & ~r) | (s & ~d & r)) & 0x8000) != 0)
        throw new ArithmeticException("short overflow sub(" + s + ", " + d + ")");
    return (short) r;
}

(নোট করুন যে উপরের উদাহরণটি প্রয়োজনের মত প্রকাশ করে বিয়োগের ওভারফ্লো সনাক্তকরণের )


তাহলে কীভাবে / কেন এই বুলিয়ান এক্সপ্রেশনগুলি কাজ করে? প্রথমত, কিছু লজিক্যাল চিন্তা জানায় যে একটি ওভারফ্লো করতে শুধুমাত্র ঘটতে উভয় আর্গুমেন্ট লক্ষণ একই। কারণ, যদি একটি যুক্তি negativeণাত্মক হয় এবং একটি ধনাত্মক হয়, ফলাফল (যুক্ত হওয়ার) অবশ্যই শূন্যের কাছাকাছি হওয়া উচিত , বা চরম ক্ষেত্রে একটি যুক্তি শূন্য, অন্য যুক্তির মতো as যেহেতু নিজেরাই যুক্তিগুলি একটি ওভারফ্লো পরিস্থিতি তৈরি করতে পারে না , তাদের যোগফল একটি ওভারফ্লোও তৈরি করতে পারে না।

সুতরাং যদি উভয় যুক্তিতে একই চিহ্ন থাকে? কেসটি উভয়ই ইতিবাচক ক্ষেত্রে একবার দেখে নেওয়া যাক: দুইটি যুক্তি যুক্ত করা যা MAX_VALUE প্রকারের চেয়ে বড় পরিমাণ তৈরি করে, সর্বদা একটি নেতিবাচক মান দেয়, সুতরাং একটি ওভারফ্লো ঘটে যদি আরগ 1 + আরগ 2> MAX_VALUE । এখন যে সর্বাধিক মানটির ফলাফল হতে পারে তা হ'ল MAX_VALUE + MAX_VALUE (চরম ক্ষেত্রে উভয় যুক্তিই MAX_VALUE)। বাইটের জন্য (উদাহরণস্বরূপ) এর অর্থ হবে 127 + 127 = 254. দুটি মানের ইতিবাচক মান যুক্ত হতে পারে এমন সমস্ত মানের বিট উপস্থাপনার দিকে তাকালে একজন দেখতে পান যে ওভারফ্লো (128 থেকে 254) সমস্ত বিট 7 সেট রয়েছে, যখন ওভারফ্লো হয় না এমন (0 থেকে 127) বিট 7 (শীর্ষস্থানীয়, সাইন) সাফ হয়েছে। এক্সপ্রেশনটির প্রথম (ডান) অংশটি যা ঠিক তা পরীক্ষা করে:

if (((s & d & ~r) | (~s & ~d & r)) < 0)

(& গুলি & ~ d & r) সত্য হয়ে যায়, কেবল যদি if উভয় অপারেশন (গুলি, ডি) ইতিবাচক হয় এবং ফলাফল (আর) নেতিবাচক হয় (এক্সপ্রেশনটি সমস্ত 32 বিটগুলিতে কাজ করে, তবে কেবলমাত্র আমরা আগ্রহী শীর্ষস্থানীয় (চিহ্ন) বিট, যা <0) দ্বারা পরীক্ষা করা হয়।

এখন যদি উভয় যুক্তিই নেতিবাচক হয় তবে তাদের যোগফল যে কোনও যুক্তির তুলনায় শূন্যের কাছাকাছি হতে পারে না, যোগফল অবশ্যই বিয়োগের অনন্তের কাছাকাছি হওয়া উচিত । আমরা যে চূড়ান্ত মানটি উত্পাদন করতে পারি তা হ'ল এমএকটিওয়ালিউ + এমটিভ্যালু, যা (আবার বাইট উদাহরণের জন্য) দেখায় যে পরিসরের মান (-1 থেকে -128) এর জন্য সাইন বিট সেট করা হয়েছে, যখন কোনও সম্ভাব্য ওভারফ্লোয়েং মান (-129 থেকে -256) ) সাইন বিট সাফ করেছে। সুতরাং ফলাফলের সাইন আবার ওভারফ্লো অবস্থাটি প্রকাশ করে। উভয় যুক্তি (গুলি, ডি) নেতিবাচক এবং ফলস্বরূপ যে ক্ষেত্রে ইতিমধ্যে বাম অর্ধেক (গুলি ও ডি & ~ আর) যা যাচাই করে তা পরীক্ষা করে ts যুক্তি মূলত পজিটিভ ক্ষেত্রে সমান; সমস্ত বিট নিদর্শনগুলি যা দুটি নেতিবাচক মান যুক্ত হওয়ার ফলে হতে পারে তাতে সাইন বিট সাফ হবে যদি এবং কেবল যদি কোনও আন্ডারফ্লো ঘটে থাকে।


1
আপনি এটি বিটওয়াইজ অপারেটরগুলির সাথেও পরীক্ষা করতে পারেন, আরও ভাল্লোগিক.com
roger/

1
এটি কাজ করবে তবে আমি ধরে নিচ্ছি এটির একটি বাজে পারফরম্যান্স হিট হবে।
চেসোফনার্ড

33

ডিফল্টরূপে, জাভা এর অন্তর্নিহিত এবং দীর্ঘ গণিত নিঃশব্দে ওভারফ্লো এবং আন্ডারফ্লোতে চারপাশে মোড়ানো। (অন্যান্য পূর্ণসংখ্যার ধরণের ইন্টিজার অপারেশনগুলি জেএলএস ৪.২.২ অনুসারে প্রথমে অপারেটরগুলিকে ইনট বা লম্বায় উন্নীত করে সম্পাদিত হয় ))

জাভা 8, এর হিসাবে java.lang.Mathপ্রদান করে addExact, subtractExact, multiplyExact, incrementExact, decrementExactএবং negateExactউভয় int- এ এবং দীর্ঘ যুক্তি হল যে নামক অপারেশনে সঞ্চালন, ওভারফ্লো উপর ArithmeticException নিক্ষেপ জন্য স্ট্যাটিক পদ্ধতি। (কোনও ডিভাইডএক্স্যাক্ট পদ্ধতি নেই - আপনাকে একটি বিশেষ কেস MIN_VALUE / -1নিজেই পরীক্ষা করতে হবে ( ) নিজেই।)

জাভা 8-এর হিসাবে, java.lang.Math এছাড়াও toIntExactদীর্ঘমেয়াদীর জন্য একটি দীর্ঘ cast ালাই সরবরাহ করে, দীর্ঘমেয়ের মানটি যদি কোনও ইনট্রে ফিট না করে তবে অ্যারিমেটিক এক্সসেপশন নিক্ষেপ করে। এটি উদাহরণস্বরূপ চেক না করা লম্বা গণিত ব্যবহার করে ইনটসের যোগফলের গণনা করার জন্য, তারপরে toIntExactপ্রান্তে কাস্ট করতে ব্যবহার করার জন্য কার্যকর হতে পারে (তবে আপনার সমষ্টিটি উপচে না পড়তে সতর্ক হন)।

আপনি যদি এখনও জাভার একটি পুরানো সংস্করণ ব্যবহার করেন তবে গুগু পেয়ারা পরীক্ষিত সংযোজন, বিয়োগ, গুণ এবং ক্ষয়ক্ষতি (ওভারফ্লোতে ছোঁড়া) জন্য ইনটম্যাথ এবং লংম্যাথ স্থিতির পদ্ধতি সরবরাহ করে। এই ক্লাসগুলি ফ্যাক্টরিয়ালগুলি এবং দ্বিপদী সহগগুলি গণনা করার পদ্ধতিও সরবরাহ করে MAX_VALUEযা ওভারফ্লোতে ফিরে আসে (যাচাই করার পক্ষে কম সুবিধাজনক)। পেয়ারা এর আদিম ইউটিলিটি ক্লাস, SignedBytes, UnsignedBytes, Shortsএবং Intsপ্রদান checkedCastবৃহত্তর প্রকার (অধীনে / ওভারফ্লো, উপর IllegalArgumentException নিক্ষেপ সংকীর্ণ জন্য পদ্ধতি না ArithmeticException), সেইসাথে saturatingCastপদ্ধতি রিটার্ন MIN_VALUEবা MAX_VALUEওভারফ্লো উপর।


32

জাভা আন্ত বা দীর্ঘ আদিম ধরণের জন্য পূর্ণসংখ্যার ওভারফ্লো দিয়ে কিছু করে না এবং ইতিবাচক এবং নেতিবাচক পূর্ণসংখ্যার সাথে ওভারফ্লো উপেক্ষা করে।

এই উত্তরটি প্রথমে পূর্ণসংখ্যার ওভারফ্লোটির বর্ণনা দেয়, এটি কীভাবে ঘটতে পারে তার উদাহরণ দেয়, এমনকি অভিব্যক্তির মূল্যায়নের মধ্যবর্তী মানগুলি সহ এবং এটি সংস্থানগুলিতে লিঙ্ক দেয় যা পূর্ণসংখ্যার ওভারফ্লো প্রতিরোধ এবং সনাক্তকরণের জন্য বিশদ কৌশল দেয়।

অপ্রত্যাশিত বা সনাক্ত না করা ওভারফ্লোতে সংখ্যার গাণিতিক এবং এক্সপ্রেশনগুলির ফলাফল একটি সাধারণ প্রোগ্রামিং ত্রুটি। অপ্রত্যাশিত বা সনাক্ত না হওয়া পূর্ণসংখ্যা ওভারফ্লোও একটি সুপরিচিত শোষণযোগ্য সুরক্ষা সমস্যা, বিশেষত এটি অ্যারে, স্ট্যাক এবং তালিকাভুক্ত বস্তুগুলিকে প্রভাবিত করে।

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

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

নিম্নলিখিত কোড বিবেচনা করুন:

int bigValue = Integer.MAX_VALUE;
int x = bigValue * 2 / 5;
int y = bigValue / x;

x এর ফলস্বরূপ x নির্ধারিত হয় এবং বিগভ্যালু / এক্স এর পরবর্তী মূল্যায়ণটি y এর পরিবর্তে মান 2 নির্ধারিত হওয়ার পরিবর্তে "ArithmeticException: / শূন্য দ্বারা" (অর্থাত শূন্য দ্বারা বিভাজন) একটি ব্যতিক্রম ছুঁড়ে দেয়।

X এর প্রত্যাশিত ফলাফলটি 858,993,458 হবে যা সর্বাধিক 2,147,483,647 এর মান মানের চেয়ে কম। তবে, পূর্ণসংখ্যার মূল্যায়ন থেকে মধ্যবর্তী ফলাফল MA এমএএক্স_ভ্যালু * 2, 4,294,967,294 হবে, যা সর্বাধিক মান মান ছাড়িয়ে যায় এবং 2 এস পরিপূরক পূর্ণসংখ্যার উপস্থাপনা অনুসারে -2 হয়। -2 / 5 এর পরবর্তী মূল্যায়ন 0 কে মূল্যায়ন করে যা এক্সকে নির্ধারিত হয়।

এক্সকে এক্সপ্রেশন হিসাবে এক্সপ্রেশনটির পুনরায় সাজানো যা নীচের কোডটি যখন মূল্যায়ন করা হয় তখন গুণনের আগে ভাগ করে দেয়:

int bigValue = Integer.MAX_VALUE;
int x = bigValue / 5 * 2;
int y = bigValue / x;

এক্স এর ফলাফল 858,993,458 বরাদ্দ করা হয়েছে এবং y নির্ধারিত 2, যা প্রত্যাশিত।

বিগভ্যালু / 5 এর মধ্যবর্তী ফলাফল হল 429,496,729 যা কোনও ইনটেলের সর্বাধিক মান অতিক্রম করে না। 429,496,729 * 2 এর পরবর্তী মূল্যায়ন কোনও পূর্বনির্মাণের সর্বাধিক মান অতিক্রম করবে না এবং প্রত্যাশিত ফলাফলটি এক্সকে নির্ধারিত হবে। Y এর জন্য মূল্যায়ন শূন্য দ্বারা ভাগ হয় না। এক্স এবং ওয়াইয়ের জন্য মূল্যায়ন প্রত্যাশার মতো কাজ করে।

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

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

প্রাক-শর্ত পরীক্ষার মধ্যে পাটিগণিতের ক্রিয়াকলাপ বা অভিব্যক্তিতে যাওয়া মানগুলি পরীক্ষা করে থাকে তা নিশ্চিত করার জন্য যে এই মানগুলির সাথে কোনও ওভারফ্লো ঘটবে না। প্রোগ্রামিং এবং ডিজাইনের জন্য এমন টেস্টিং তৈরি করা দরকার যা নিশ্চিত করে যে ইনপুট মানগুলি ওভারফ্লো হতে না পারে এবং তারপরে নির্ধারণ করে যে ইনপুট মানগুলি দেখা দেয় যা ওভারফ্লো হতে পারে what

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

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

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

পূর্ণসংখ্যা ওভারফ্লো প্রতিরোধ বা সনাক্তকরণের কোডিং কৌশলগুলির ব্যবহারিক উদাহরণগুলির মধ্যে স্ট্যান্ডার্ডের বিভাগটি এখানে রয়েছে: NUM00-J। পূর্ণসংখ্যা ওভারফ্লো সনাক্ত করুন বা প্রতিরোধ করুন

জাভার জন্য দ্য সিইআরটি ওরাকল সিকিউর কোডিং স্ট্যান্ডার্ডের বই ফর্ম এবং পিডিএফ ফর্মটি উপলব্ধ।


যেমন স্পষ্টভাবে underflow কি এই সর্বোত্তম উত্তর এখানে (গৃহীত উত্তর না) এবং / underflow ওভারফ্লো সঙ্গে তার আচরণ জন্য কৌশল তালিকাবদ্ধ করে
নাভি

12

আমি নিজেই এই সমস্যার মধ্যে দৌড়াদৌড়ি করার পরে, আমার সমাধানটি এখানে (গুণ এবং সংযোজন উভয়ের জন্য):

static boolean wouldOverflowOccurwhenMultiplying(int a, int b) {
    // If either a or b are Integer.MIN_VALUE, then multiplying by anything other than 0 or 1 will result in overflow
    if (a == 0 || b == 0) {
        return false;
    } else if (a > 0 && b > 0) { // both positive, non zero
        return a > Integer.MAX_VALUE / b;
    } else if (b < 0 && a < 0) { // both negative, non zero
        return a < Integer.MAX_VALUE / b;
    } else { // exactly one of a,b is negative and one is positive, neither are zero
        if (b > 0) { // this last if statements protects against Integer.MIN_VALUE / -1, which in itself causes overflow.
            return a < Integer.MIN_VALUE / b;
        } else { // a > 0
            return b < Integer.MIN_VALUE / a;
        }
    }
}

boolean wouldOverflowOccurWhenAdding(int a, int b) {
    if (a > 0 && b > 0) {
        return a > Integer.MAX_VALUE - b;
    } else if (a < 0 && b < 0) {
        return a < Integer.MIN_VALUE - b;
    }
    return false;
}

ভুল হলে বা সরল করা যেতে পারে নিখরচায়। আমি গুণের পদ্ধতিতে কিছু পরীক্ষা করেছি, বেশিরভাগ প্রান্তের কেস, তবে এটি এখনও ভুল হতে পারে।


বিভাগটি গুণনের তুলনায় ধীর হতে উপযুক্ত। কারণ int*int, আমি মনে করি কেবল কাস্টিং করা longএবং ফলাফলটি intসবচেয়ে দ্রুততম পদ্ধতির সাথে খাপ খায় কিনা তা দেখার জন্য । কারণ long*long, যদি কেউ অপারেশনকে ধনাত্মক হিসাবে স্বাভাবিক করে তোলে তবে প্রত্যেকটি উপরের এবং নিম্ন 32-বিট অর্ধেককে বিভক্ত করতে পারে, প্রতিটি অর্ধেক দীর্ঘকে উন্নীত করতে পারে (সাইন এক্সটেনশনগুলি সম্পর্কে সতর্কতা অবলম্বন করুন!) এবং তারপরে দুটি আংশিক পণ্য গণনা করুন [উপরের অংশগুলির একটিতে হওয়া উচিত) শূন্য হতে]।
সুপারক্যাট

আপনি যখন "দীর্ঘ * দীর্ঘকাল ধরে বলছেন, যদি কেউ অপারেশনকে ইতিবাচক হতে ..." বলে থাকে, আপনি লংকে কীভাবে স্বাভাবিক করবেন?

এই পদ্ধতিগুলি আকর্ষণীয় হতে পারে যদি পরীক্ষার প্রয়োজন হয় যদি আসলে গণনা সম্পাদন করার আগে কিছু উপচে পড়ে । এটি পরীক্ষার জন্য দুর্দান্ত হতে পারে যেমন ব্যবহারকারীর ইনপুট যা এই জাতীয় গণনার জন্য ব্যবহৃত হয়, যখন এটি ঘটে তখন ব্যতিক্রম ধরা না instead
মার্টেন বোদেউয়েস

8

এমন লাইব্রেরি রয়েছে যা সুরক্ষিত গাণিতিক ক্রিয়াকলাপ সরবরাহ করে, যা পূর্ণসংখ্যার ওভারফ্লো / আন্ডারফ্লো পরীক্ষা করে। উদাহরণস্বরূপ, পেয়ারা'র ইন্টারম্যাথ.কমেকডএড (ইনট্রে, ইনট বি) যোগফল প্রদান করে aএবং bসরবরাহ করে যে এটি উপচে না পড়ে এবং ArithmeticExceptionযদি a + bস্বাক্ষরিত intগাণিতিকগুলিতে ওভারফ্লো হয় তবে ছোঁড়ে ।


হ্যাঁ, আপনি যদি জাভা 8 বা তার বেশি না হন, তবে Mathক্লাসে একই রকম কোড রয়েছে unless
মার্টেন বোদেউয়েস

6

এটি চারপাশে মোড়ানো।

উদাহরণ:

public class Test {

    public static void main(String[] args) {
        int i = Integer.MAX_VALUE;
        int j = Integer.MIN_VALUE;

        System.out.println(i+1);
        System.out.println(j-1);
    }
}

কপি করে প্রিন্ট

-2147483648
2147483647

আমরা হব! এবং এখন, আপনি উত্তর দিতে পারেন, কীভাবে এটি জটিল ক্যালকুলাসে সনাক্ত করবেন?
আউবিন

5

আমি মনে করি আপনার এই জাতীয় কিছু ব্যবহার করা উচিত এবং এটি আপকাস্টিং নামে পরিচিত:

public int multiplyBy2(int x) throws ArithmeticException {
    long result = 2 * (long) x;    
    if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE){
        throw new ArithmeticException("Integer overflow");
    }
    return (int) result;
}

আপনি এখানে আরও পড়তে পারেন: পূর্ণসংখ্যা ওভারফ্লো সনাক্ত করুন বা প্রতিরোধ করুন

এটি বেশ নির্ভরযোগ্য উত্স।


3

এটি কিছুই করে না - আন্ডার / ওভারফ্লো কেবল ঘটে।

একটি "-1" যা একটি গণনার ফলাফল যা উপচে পড়েছে অন্য কোনও তথ্য থেকে প্রাপ্ত "-1" থেকে আলাদা নয়। সুতরাং আপনি কিছু স্ট্যাটাসের মাধ্যমে বা এটি কোনও উপচে পড়েছে কিনা তার মূল্য নির্ধারণের মাধ্যমে বলতে পারবেন না।

ওভারফ্লো এড়াতে আপনি যদি নিজের কম্পিউটেশন সম্পর্কে স্মার্ট হতে পারেন তবে তা গুরুত্বপূর্ণ, বা কখন তা ঘটবে তা কমপক্ষে জানেন। আপনার অবস্থা কি?


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

1
static final int safeAdd(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left > Integer.MAX_VALUE - right
                : left < Integer.MIN_VALUE - right) {
    throw new ArithmeticException("Integer overflow");
  }
  return left + right;
}

static final int safeSubtract(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left < Integer.MIN_VALUE + right
                : left > Integer.MAX_VALUE + right) {
    throw new ArithmeticException("Integer overflow");
  }
  return left - right;
}

static final int safeMultiply(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left > Integer.MAX_VALUE/right
                  || left < Integer.MIN_VALUE/right
                : (right < -1 ? left > Integer.MIN_VALUE/right
                                || left < Integer.MAX_VALUE/right
                              : right == -1
                                && left == Integer.MIN_VALUE) ) {
    throw new ArithmeticException("Integer overflow");
  }
  return left * right;
}

static final int safeDivide(int left, int right)
                 throws ArithmeticException {
  if ((left == Integer.MIN_VALUE) && (right == -1)) {
    throw new ArithmeticException("Integer overflow");
  }
  return left / right;
}

static final int safeNegate(int a) throws ArithmeticException {
  if (a == Integer.MIN_VALUE) {
    throw new ArithmeticException("Integer overflow");
  }
  return -a;
}
static final int safeAbs(int a) throws ArithmeticException {
  if (a == Integer.MIN_VALUE) {
    throw new ArithmeticException("Integer overflow");
  }
  return Math.abs(a);
}

2
এটি পরীক্ষা পরিচালনা করে। যদিও জাভা কীভাবে পূর্ণসংখ্যার আন্ডারফ্লো এবং ওভারফ্লোগুলি পরিচালনা করে তা ব্যাখ্যা করে না (ব্যাখ্যা করার জন্য কিছু পাঠ্য যুক্ত করুন)।
স্প্যান্সার ওয়াইকজোরেক 21

1

আমি মনে করি এটি ঠিক করা উচিত।

static boolean addWillOverFlow(int a, int b) {
    return (Integer.signum(a) == Integer.signum(b)) && 
            (Integer.signum(a) != Integer.signum(a+b)); 
}

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