জাভাতে দুটি সংখ্যাকে গুণিত করার ফলে ওভারফ্লো হবে কিনা আমি কীভাবে তা পরীক্ষা করতে পারি?


101

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

int a = 20;
long b = 30;

// if a or b are big enough, this result will silently overflow
long c = a * b;

এটি একটি সরলীকৃত সংস্করণ। আসল প্রোগ্রামে aএবং bরানটাইমে অন্য কোথাও উত্সাহিত হয়। আমি যা অর্জন করতে চাই তা হ'ল:

long c;
if (a * b will overflow) {
    c = Long.MAX_VALUE;
} else {
    c = a * b;
}

আপনি কীভাবে আমার সেরা কোডটির পরামর্শ দিচ্ছেন?

আপডেট: aএবং bআমার দৃশ্যে সর্বদা অ-নেতিবাচক থাকে।


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

উত্তর:


93

জাভা 8 হয়েছে Math.multiplyExact, Math.addExactints জন্য এবং দীর্ঘ ইত্যাদি। এগুলি ArithmeticExceptionওভারফ্লোতে একটি চেক করা ছাড়াই ফেলে দেয় ।


59

যদি aএবং bউভয়ই ইতিবাচক হয় তবে আপনি ব্যবহার করতে পারেন:

if (a != 0 && b > Long.MAX_VALUE / a) {
    // Overflow
}

আপনার যদি ইতিবাচক এবং নেতিবাচক উভয় সংখ্যার সাথে ডিল করতে হয় তবে এটি আরও জটিল:

long maximum = Long.signum(a) == Long.signum(b) ? Long.MAX_VALUE : Long.MIN_VALUE;

if (a != 0 && (b > 0 && b > maximum / a ||
               b < 0 && b < maximum / a))
{
    // Overflow
}

এটি পরীক্ষা করার জন্য আমি এখানে একটি ছোট্ট টেবিলটি চাপলাম, ভেবে যে -10 বা +10 এ ওভারফ্লো হয়:

a =  5   b =  2     2 >  10 /  5
a =  2   b =  5     5 >  10 /  2
a = -5   b =  2     2 > -10 / -5
a = -2   b =  5     5 > -10 / -2
a =  5   b = -2    -2 < -10 /  5
a =  2   b = -5    -5 < -10 /  2
a = -5   b = -2    -2 <  10 / -5
a = -2   b = -5    -5 <  10 / -2

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

4
আমি এই একটি ক্ষেত্রে ব্যর্থ হতে পারে: একটি = -1 ও b = 10. সর্বোচ্চ / Integer.MIN_VALUE একটি অভিব্যক্তি ফলাফলের এবং ওভারফ্লো সনাক্ত করে যখন কেউ অস্তিত্ব
কাইলি

এটি সত্যিই দুর্দান্ত। ভাবছি তাদের জন্য, কারণ এই কাজ করে পূর্ণসংখ্যা জন্য n, n > xহিসাবে একই n > floor(x)। ধনাত্মক পূর্ণসংখ্যা বিভাগের জন্য একটি নিখুঁত মেঝে করে। (নেতিবাচক সংখ্যার জন্য এটি পরিবর্তে
টমাস আহলে

মোকাবেলার a = -1এবং b = 10ইস্যু, নীচের আমার উত্তর দেখুন।
জিম পিভারস্কি

17

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


4
এটি সেরা উত্তর - একটি লাইব্রেরি ব্যবহার করুন যা জাভাতে মেশিনগণিতগণিত সত্যই বুঝতে পেরেছিলেন এবং এটি প্রচুর লোক দ্বারা পরীক্ষিত হয়েছে implemented আপনার নিজের লেখার চেষ্টা করবেন না বা অন্য উত্তরে পোস্ট হওয়া অর্ধ-বেকড অচিহ্নিত কোড ব্যবহার করুন!
ধনী

@ আন্তর্সিও - আমি আপনার মন্তব্য বুঝতে পারি না। আপনি কি বলছেন যে পেয়ারা সমস্ত সিস্টেমে কাজ করবে না? আমি আপনাকে আশ্বস্ত করতে পারি যে এটি জাভা যেখানেই কাজ করে work আপনি কি বলছেন যে কোডটি পুনরায় ব্যবহার করা সাধারণভাবে একটি খারাপ ধারণা? যদি তাই হয় তবে আমি একমত নই।
ধনী

4
@ সমৃদ্ধ আমি বলছি বিশাল লাইব্রেরি সহ আপনি যাতে একটি ফাংশন ব্যবহার করতে পারেন এটি একটি খারাপ ধারণা।
এনারসিসিও

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

শর্তসাপেক্ষ কোনও কিছুর জন্য যদি ব্যতিক্রম কিছুটা ওভারকিল নিক্ষেপ করা হয় না তবে কি তা পরিচালনা করতে পারে?
victtim

6

আপনি এর পরিবর্তে java.math.BigInteger ব্যবহার করতে পারেন এবং ফলাফলের আকারটি পরীক্ষা করতে পারেন (কোডটি পরীক্ষা করেন নি):

BigInteger bigC = BigInteger.valueOf(a) * multiply(BigInteger.valueOf(b));
if(bigC.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
  c = Long.MAX_VALUE;
} else {
  c = bigC.longValue()
}

7
আমি এই সমাধানটি বরং ধীর
পেয়েছি

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

4
আমি নিশ্চিত না যে আপনি বিগইন্টিজারের সাথে '>' অপারেটরটি ব্যবহার করতে পারবেন। তুলনামূলক পদ্ধতি ব্যবহার করা উচিত।
পিয়েরে

তুলনা করার জন্য পরিবর্তিত হয়েছে, এবং গতি কিছুটা গুরুত্বপূর্ণ বা নাও হতে পারে তার উপর নির্ভর করে কোডটি কখন ব্যবহৃত হবে।
উলফ লিন্ডব্যাক

5

ফলাফলের আকারটি পরীক্ষা করতে লগারিদম ব্যবহার করুন।


আপনি কি এটি বলতে না: ceil(log(a)) + ceil(log(b)) > log(Long.MAX)?
থমাস জং

4
আমি এটি পরীক্ষা করেছিলাম। ছোট মানগুলির জন্য এটি বিগইন্টেগারের চেয়ে 20% দ্রুত এবং ম্যাক্সের কাছাকাছি মানের জন্য এটি প্রায় একই (5% দ্রুত)। ইওসারিয়ার কোডটি দ্রুততম (বিগইন্টিজারের চেয়ে 95% এবং 75% দ্রুত)।
থমাস জং

আমি বরং সন্দেহ করি যে এটি কিছু ক্ষেত্রে ব্যর্থ হতে পারে।
টম হাটিন -

মনে রাখবেন একটি পূর্ণসংখ্যার লগ কার্যকরভাবে কেবল শীর্ষস্থানীয় শূন্যের সংখ্যা গণনা করা হয় এবং আপনি কয়েকটি সাধারণ ক্ষেত্রে (যেমন ((a | b) & 0xffffffff00000000L) == 0) জানেন যে আপনি নিরাপদ)) অন্যদিকে, আপনি আপনার ক্ষেত্রে সবচেয়ে সাধারণ ক্ষেত্রে 30/40-hশ ঘড়ির চক্রের নীচে নেমে না আসতে পারলে জন কুগেলম্যানের পদ্ধতি সম্ভবত আরও ভাল সম্পাদন করবে (আমার মনে পড়ার সাথে একটি পূর্ণসংখ্যা বিভাগ সি। 2 বিট / ক্লক চক্র))
নিল কফফি

পিএস সোর, আমার মনে হয় এ্যান্ডএইড মাস্কে আমার একটি অতিরিক্ত বিট সেট লাগবে (0xffffffff80000000L) - কিছুটা দেরী হলেও আপনি ধারণাটি পেয়েছেন ...
নীল কফফি

4

জাভাতে কি int.MaxValue এর মতো কিছু আছে? যদি হ্যাঁ, তবে চেষ্টা করুন

if (b != 0 && Math.abs(a) > Math.abs(Long.MAX_VALUE / b))
{
 // it will overflow
}

সম্পাদনা: দীর্ঘ প্রশ্নে দেখা গেছে MA MAX_VALUE


আমি downvote করা হয়নি কিন্তু Math.Abs(a)যদি না কাজ করে aহয় Long.MIN_VALUE
জন কুগেলম্যান

@ জন - ক এবং বি> ০. আমি মনে করি ইওসারিয়ারের পদ্ধতির (খ! = 0 && এ> লং।ম্যাক্স_ভ্যালু / বি) সেরা।
থমাস জং

@ থমাস, এ এবং বি হল = =, যা অ-নেতিবাচক।
স্টিভ ম্যাকলিউড

4
ঠিক আছে, তবে সে ক্ষেত্রে অ্যাবসের দরকার নেই no যদি নেতিবাচক সংখ্যাগুলি অনুমোদিত হয় তবে এটি কমপক্ষে একটি প্রান্ত ক্ষেত্রে ব্যর্থ। আমি শুধু বলছি, নিটপিকি হচ্ছে।
জন কুগেলম্যান

জাভাতে আপনাকে ম্যাথ.অ্যাবস ব্যবহার করতে হবে, ম্যাথ নয়। অ্যাবস (সি # লোক?)
dfa

4

আমি ভাবতে পারি সবচেয়ে সহজ উপায় এখানে

int a = 20;
long b = 30;
long c = a * b;

if(c / b == a) {
   // Everything fine.....no overflow
} else {
   // Overflow case, because in case of overflow "c/b" can't equal "a"
}

3

জুরবি থেকে চুরি

    long result = a * b;
    if (a != 0 && result / a != b) {
       // overflow
    }

আপডেট: এই কোডটি সংক্ষিপ্ত এবং ভালভাবে কাজ করে; তবে এটি একটি = -1, বি = লং.এম.এক.এল.এল.এই.পি.

একটি সম্ভাব্য বর্ধন:

long result = a * b;
if( (Math.signum(a) * Math.signum(b) != Math.signum(result)) || 
    (a != 0L && result / a != b)) {
    // overflow
}

নোট করুন যে এটি কোনও বিভাগ ছাড়াই কিছু ওভারফ্লোগুলি ধরবে।


আপনি ম্যাথ.সাইনামের পরিবর্তে লং.সাইনাম ব্যবহার করতে পারেন
অ্যাডিটসু প্রস্থান করুন কারণ এসই ইভিল

3

হিসাবে চিহ্নিত করা হয়েছে, জাভা 8 এর মধ্যে ম্যাথ.এক্সএক্সএক্সএক্স্যাক্ট পদ্ধতি রয়েছে যা ওভারফ্লোতে ব্যতিক্রম ছুঁড়ে ফেলে।

আপনি যদি আপনার প্রকল্পের জন্য জাভা 8 ব্যবহার না করে থাকেন তবে আপনি এখনও তাদের বাস্তবায়নগুলি "ধার" নিতে পারেন যা বেশ কমপ্যাক্ট।

এখানে জেডি কে সোর্স কোড ভান্ডারে এই বাস্তবায়নগুলির কয়েকটি লিঙ্ক রয়েছে, এগুলি বৈধ থাকবে কিনা তার কোনও গ্যারান্টি নেই তবে যে কোনও ক্ষেত্রে আপনি জেডিকে উত্স ডাউনলোড করতে সক্ষম হন এবং java.lang.Mathক্লাসের মধ্যে কীভাবে তারা তাদের যাদু করেন তা দেখুন ।

Math.multiplyExact(long, long) http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/class/java/lang/Math.java#l925

Math.addExact(long, long) http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/class/java/lang/Math.java#l830

ইত্যাদি, ইত্যাদি

আপডেট হয়েছে: তৃতীয় পক্ষের ওয়েবসাইটটিতে অবৈধ লিঙ্কগুলি ওপেন জেডিকে এর মার্চুরিয়াল রিপোজিটরিগুলির লিঙ্কগুলিতে স্যুইচ করেছে।


2

আমি নিশ্চিত না যে কেন কেউ সমাধানের দিকে তাকাচ্ছে না:

if (Long.MAX_VALUE/a > b) {
     // overflows
} 

দুটি সংখ্যার চেয়ে বড় হতে বেছে নিন।


4
আমি মনে করি না যে এটির aচেয়ে বড় বা ছোটটি গুরুত্বপূর্ণ?
টমাস আহলে

2

আমি জন কুগেলম্যানের উত্তরটি সরাসরি সম্পাদনা করে প্রতিস্থাপন না করেই তৈরি করতে চাই। এটি তার পরীক্ষার কেস ( MIN_VALUE = -10, MAX_VALUE = 10) এর প্রতিসাম্যের কারণে কাজ করে MIN_VALUE == -MAX_VALUEযা দুজনের পরিপূরক পূর্ণসংখ্যার ক্ষেত্রে হয় না। বাস্তবে MIN_VALUE == -MAX_VALUE - 1,।

scala> (java.lang.Integer.MIN_VALUE, java.lang.Integer.MAX_VALUE)
res0: (Int, Int) = (-2147483648,2147483647)

scala> (java.lang.Long.MIN_VALUE, java.lang.Long.MAX_VALUE)
res1: (Long, Long) = (-9223372036854775808,9223372036854775807)

সত্যের সাথে প্রয়োগ করা হলে MIN_VALUEএবং MAX_VALUEজন কুগেলম্যানের উত্তর কখন a == -1এবং b ==অন্য যে কোনও কিছু (কাইল প্রথম উত্থাপিত পয়েন্ট) একটি ওভারফ্লো কেস দেয় । এটি ঠিক করার জন্য এখানে একটি উপায়:

long maximum = Long.signum(a) == Long.signum(b) ? Long.MAX_VALUE : Long.MIN_VALUE;

if ((a == -1 && b == Long.MIN_VALUE) ||
    (a != -1 && a != 0 && ((b > 0 && b > maximum / a) ||
                           (b < 0 && b < maximum / a))))
{
    // Overflow
}

এটা কোনো জন্য একটি সাধারণ সমাধান না MIN_VALUEএবং MAX_VALUE, কিন্তু এটা জাভার জন্য সাধারণ Longএবং Integerএবং কোনো মান aএবং b


আমি কেবল ভেবেছিলাম এটি অযথা এটি জটিল করে তুলবে, যেহেতু এই সমাধানটি কেবল তখনই কাজ করে MIN_VALUE = -MAX_VALUE - 1, অন্য কোনও মামলা নয় (আপনার উদাহরণ পরীক্ষার উদাহরণ সহ)। আমাকে অনেক পরিবর্তন করতে হবে
জিম পিভারস্কি

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

1

হতে পারে:

if(b!= 0 && a * b / b != a) //overflow

এই "সমাধান" সম্পর্কে নিশ্চিত নয়।

সম্পাদনা করুন: খ! = 0 যুক্ত হয়েছে

আপনি ডাউনটিভোট করার আগে : একটি * বি / বি অনুকূলিত হবে না। এটি সংকলক বাগ হবে। ওভারফ্লো বাগটি মাস্ক করা যেতে পারে এমন কোনও মামলা এখনও আমি দেখতে পাচ্ছি না।


ওভারফ্লো যখন নিখুঁত লুপের কারণ হয়ে যায় তখনও ব্যর্থ হয়।
স্টিফান কেন্ডাল

আপনি কী বোঝাতে চেয়েছিলেন তার উদাহরণ আছে?
থমাস জং

কেবলমাত্র একটি সামান্য পরীক্ষা লিখেছেন: বিগইন্টিজার ব্যবহার এই বিভাগের পদ্ধতির ব্যবহারের চেয়ে 6 গুণ ধীর। সুতরাং আমি ধরে নিই কোণার কেসগুলির জন্য অতিরিক্ত চেকগুলি কার্য সম্পাদন অনুযায়ী মূল্যবান।
মহল্লার

জাভা সংকলক সম্পর্কে খুব বেশি কিছু জানেন না, তবে এর মত একটি এক্সপ্রেশনটি অন্যান্য অনেক প্রসঙ্গে a * b / bকেবল অনুকূলিত হতে পারে a
সিঙ্গেলাইজেশন ইলিমিনেশন

টোকেনম্যাকগুয়ে - যদি ওভারফ্লো হওয়ার আশঙ্কা থাকে তবে এটি এমনটি অনুকূল করা যায় না।
টম হাটিন -

1

হয়তো এই আপনাকে সাহায্য করবে:

/**
 * @throws ArithmeticException on integer overflow
 */
static long multiply(long a, long b) {
    double c = (double) a * b;
    long d = a * b;

    if ((long) c != d) {
        throw new ArithmeticException("int overflow");
    } else {
        return d;
    }
}

অপারেটরগুলির একটি হিসাবে সহায়তা করবে না long
টম হাটিন -

4
আপনি কি এটি পরীক্ষা করেছেন? কোনও & বি এর বৃহত্তর তবে উপচে পড়া মানের জন্য এটি গুণটির ডাবল সংস্করণে গোলাকার ত্রুটির কারণে ব্যর্থ হবে (উদাহরণস্বরূপ 123456789123L এবং 74709314L চেষ্টা করুন)। আপনি যদি মেশিন পাটিগণিত না বুঝতে পারেন তবে এই ধরণের সুনির্দিষ্ট প্রশ্নের উত্তর অনুমান করা উত্তর না দেওয়ার চেয়ে খারাপ, কারণ এটি লোককে বিভ্রান্ত করবে।
ধনী

-1

সি / সি ++ (দীর্ঘ * দীর্ঘ):

const int64_ w = (int64_) a * (int64_) b;    
if ((long) (w >> sizeof(long) * 8) != (long) w >> (sizeof(long) * 8 - 1))
    // overflow

জাভা (ইনট * ইন, দুঃখিত, আমি জাভাতে অন্তত 64 খুঁজে পাইনি):

const long w = (long) a * (long) b;    
int bits = 32; // int is 32bits in java    
if ( (int) (w >> bits) != (int) (w >> (bits - 1))) {
   // overflow
}

১. ফলাফলটি বড় ধরণের সংরক্ষণ করুন (ফলাফল * দীর্ঘ, দীর্ঘ * দীর্ঘ int৪ তে রেখে দিন)

2.cmp ফলাফল >> বিট এবং ফলাফল >> (বিট - 1)

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