আমি কেন আমাকে = আমি + দিই?


96

আমার একটি সহজ প্রোগ্রাম রয়েছে:

public class Mathz {
    static int i = 1;
    public static void main(String[] args) {    
        while (true){
            i = i + i;
            System.out.println(i);
        }
    }
}

যখন আমি এই প্রোগ্রাম চালানো, সব দেখছি যে আমাদের 0জন্য iআমার আউটপুটে। আমি আমাদের প্রথমবারের মতো আশা করব i = 1 + 1, তার পরে i = 2 + 2, তারপরে i = 4 + 4ইত্যাদি by

এটি কি এই কারণে যে আমরা iবাম দিকে আবার ঘোষণার চেষ্টা করার সাথে সাথে এর মানটি আবার সেট হয়ে যায় 0?

যদি কেউ আমাকে এর সূক্ষ্ম বিবরণে নির্দেশ করতে পারে তবে তা দুর্দান্ত।

পরিবর্তন intকরার জন্য longএবং এটি সংখ্যার মুদ্রণ হবে বলে আশা করা যেমন বলে মনে হয়। আমি সর্বোচ্চ 32-বিট মানটিকে কতটা হিট করে তা দেখে আমি অবাক!

উত্তর:


168

সমস্যাটি পূর্ণসংখ্যার অতিরিক্ত প্রবাহের কারণে।

32-বিট দ্বিগুণ-পরিপূরক পাটিগণ্যে:

iপাওয়ার-অফ-দুটির মান থাকা শুরু করে না তবে একবার 2 30 এ পৌঁছে গেলে ওভারফ্লো আচরণ শুরু হয় :

2 30 + 2 30 = -2 31

-2 31 + -2 31 = 0

... intগাণিতিক ক্ষেত্রে, যেহেতু এটি মূলত গাণিতিক মোড 2 ^ 32।


28
আপনি আপনার উত্তর কিছুটা প্রসারিত করতে পারেন?
ডিআইআইএস

17
@oOTesterOo এটি 2, 4 ইত্যাদি প্রিন্টিংয়ের শুরু হয় তবে এটি খুব দ্রুত পূর্ণসংখ্যার সর্বাধিক মানতে পৌঁছে যায় এবং এটি নেতিবাচক সংখ্যায় "মোড়ানো" হয়ে যায়, এটি একবার শূন্যে পৌঁছে গেলে তা চিরতরে শূন্যে থেকে যায়
রিচার্ড টিংল

52
এই উত্তরটি এমনকি সম্পূর্ণ হয়েছে (এটা এমনকি করে না উল্লেখ যে মান হবে না হতে 0প্রথম কয়েক পুনরাবৃত্তিও, কিন্তু আউটপুট গতি ওপি থেকে যে সত্য আড়াল করার)। কেন এটি গৃহীত হয়?
অরবিট

16
সম্ভবত এটি গ্রহণ করা হয়েছিল কারণ এটি ওপি দ্বারা সহায়ক হিসাবে বিবেচিত হয়েছিল।
জো

4
@ লাইটনেসেসেসিনআরবিট যদিও ওপ তাদের প্রশ্নে উত্থাপিত সমস্যাগুলি সরাসরি সমাধান করে না, উত্তরটি যথেষ্ট তথ্য দেয় যে কোনও শালীন প্রোগ্রামার কী ঘটছে তা নির্ধারণ করতে সক্ষম হতে হবে।
কেভিন

334

ভূমিকা

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

একটি ওডোমিটারে, তাই max digit = 9, সর্বোচ্চ উপায় ছাড়িয়ে যাওয়া 9 + 1, যা বহন করে এবং দেয় 0; তবে 1একটিতে পরিবর্তনের জন্য কোনও উচ্চতর অঙ্ক নেই , তাই কাউন্টারটি পুনরায় সেট করে zero। আপনি ধারণাটি পান - "পূর্ণসংখ্যার ওভারফ্লোস" এখন মনে পড়ে।

এখানে চিত্র বর্ণনা লিখুন এখানে চিত্র বর্ণনা লিখুন

টাইপ এর বৃহত্তম দশমিক আক্ষরিক 2147483647 (2 31 -1)। 0 থেকে 2147483647 পর্যন্ত সমস্ত দশমিক আক্ষরিক কোথাও উপস্থিত হতে পারে যেখানে কোনও অন্তর্গত আক্ষরিক উপস্থিত হতে পারে, তবে আক্ষরিক 2147483648 কেবল অ্যানারি নেগ্রেশন অপারেটরের অপারেন্ড হিসাবে উপস্থিত হতে পারে -।

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

সুতরাং, 2147483647 + 1ওভারফ্লো এবং চারপাশে মোড়ানো -2147483648। অতএব int i=2147483647 + 1উপচে পড়া হবে, যা এর সমান নয় 2147483648। এছাড়াও, আপনি বলেছেন "এটি সর্বদা 0 প্রিন্ট করে"। এটি হয় না, কারণ http://ideone.com/WHrQIW । নীচে, এই 8 টি সংখ্যাটি যে বিন্দুতে এটি পিভটস এবং উপচে পড়েছে তা দেখায়। এটি 0s মুদ্রণ শুরু হয়। এছাড়াও, এটি কত দ্রুত গণনা করে অবাক হবেন না, আজকের মেশিনগুলি দ্রুত।

268435456
536870912
1073741824
-2147483648
0
0
0
0

কেন পূর্ণসংখ্যা ওভারফ্লো "চারপাশে মোড়ানো"

আসল পিডিএফ


17
আমি প্রতীকী উদ্দেশ্যে "প্যাকম্যান" এর জন্য অ্যানিমেশনটি যুক্ত করেছি তবে এটি কীভাবে 'পূর্ণসংখ্যার ওভারফ্লো' দেখতে পাবে তার দুর্দান্ত দৃশ্য হিসাবে কাজ করে।
আলী গাজানী

9
এটি সর্বদা সর্বদা এই সাইটে আমার প্রিয় উত্তর।
লি হোয়াইট

4
আপনি মিস করেছেন বলে মনে হচ্ছে এটি একটি দ্বিগুণ ক্রম ছিল, একটি যোগ করে না।
পাওলো ইবারম্যান

4
আমি মনে করি প্যাকম্যান অ্যানিমেশনটি এই উত্তরটি গৃহীত উত্তরের চেয়ে বেশি উত্স পেয়েছে। আমার উপর আরেকটি উত্সাহ দিন - এটি আমার প্রিয় গেমগুলির মধ্যে একটি!
হুসম্যান

4
: যেকেউ যারা প্রতীক পান নি en.wikipedia.org/wiki/Kill_screen#Pac-Man
wei2912

46

না এটি কেবল জিরো মুদ্রণ করে না।

এটিতে এটি পরিবর্তন করুন এবং আপনি দেখতে পাবেন কী ঘটে।

    int k = 50;
    while (true){
        i = i + i;
        System.out.println(i);
        k--;
        if (k<0) break;
    }

যা ঘটে তাকে ওভারফ্লো বলা হয়।


61
লুপের জন্য একটি লিখার আকর্ষণীয় উপায় :)
বার্নহার্ড

17
@ বার্নহার্ড সম্ভবত ওপি'র প্রোগ্রামটির কাঠামো বজায় রাখার জন্য।
তাইমির

4
@ টেইমার সম্ভবত, তবে তারপরেই তিনি এর trueসাথে প্রতিস্থাপন করতে পারতেন i<10000:)
বার্নহার্ড

7
আমি কেবল কয়েকটি বিবৃতি যুক্ত করতে চেয়েছিলাম; কোনও বিবৃতি মোছা / পরিবর্তন না করে। আমি অবাক হয়েছি এটি এত বিস্তৃত মনোযোগ আকর্ষণ করেছে।
পিটার.পেট্রভ

18
আপনি গোপন অপারেটর ব্যবহার করতে পারতেন while(k --> 0)কথ্য নামে "যখন kচলে যায় 0";)
লরেন্ট এলএ Rizza

15
static int i = 1;
    public static void main(String[] args) throws InterruptedException {
        while (true){
            i = i + i;
            System.out.println(i);
            Thread.sleep(100);
        }
    }

আউট পুট:

2
4
8
16
32
64
...
1073741824
-2147483648
0
0

when sum > Integer.MAX_INT then assign i = 0;

4
হুম, না, এটি শূন্যে পেতে এই নির্দিষ্ট ক্রমের জন্য কাজ করে। 3 দিয়ে শুরু করার চেষ্টা করুন
পাওলো ইবারম্যান

4

যেহেতু আমার যথেষ্ট খ্যাতি নেই আমি নিয়ন্ত্রিত আউটপুট সহ সিটিতে একই প্রোগ্রামের আউটপুটটির ছবি পোস্ট করতে পারি না, আপনি নিজে চেষ্টা করে দেখতে পারেন যে এটি আসলে 32 বার প্রিন্ট করে এবং তারপরে ওভারফ্লোর কারণে ব্যাখ্যা করা হয়েছে আমি = 1073741824 + 1073741824 পরিবর্তিত -2147483648 এবং আরও একটি আরও উপরন্তু int- এ এবং করিয়া সীমার বাইরে Zero

#include<stdio.h>
#include<conio.h>

int main()
{
static int i = 1;

    while (true){
        i = i + i;
      printf("\n%d",i);
      _getch();
    }
      return 0;
}

4
এই প্রোগ্রামটি সি-তে প্রকৃতপক্ষে প্রতিটি নির্বাহের ক্ষেত্রে অপরিজ্ঞাত আচরণকে ট্রিগার করে, যা সংকলকটিকে পুরো প্রোগ্রামটিকে কোনও কিছুর সাথে প্রতিস্থাপন করতে দেয় (এমনকি system("deltree C:")আপনি ডস / উইন্ডোতে থাকায় )। স্বাক্ষরযুক্ত পূর্ণসংখ্যা ওভারফ্লো জাভা থেকে আলাদা সি / সি ++ এ অপরিজ্ঞাত আচরণ। এই ধরণের কনস্ট্রাক্ট ব্যবহার করার সময় খুব সাবধান হন।
ফিলক্যাব

@ ফিলক্যাব: আপনি কী সম্পর্কে বলছেন "পুরো প্রোগ্রামটি কোনও কিছুর সাথে প্রতিস্থাপন করুন" । আমি ভিজ্যুয়াল স্টুডিও 2012 এ এই প্রোগ্রামটি signed and unsigned
চালিয়েছি এবং

4
@ কাইফাই: জরিমানা কাজ করা একদম বৈধ অপরিজ্ঞাত আচরণ। যাইহোক কল্পনা করুন যে কোডটি i += i32+ পুনরাবৃত্তির জন্য করেছিল, তারপরে if (i > 0)। সংকলকটি এটিকে অপ্টিমাইজ করতে পারে if(true)যেহেতু আমরা যদি সর্বদা ইতিবাচক সংখ্যা যুক্ত করি তবে সর্বদা i0 এর চেয়ে বড় হবে It যেহেতু সংকলকটি সেই কোড থেকে দুটি সমানভাবে বৈধ প্রোগ্রাম তৈরি করতে পারে, এটি নির্ধারিত আচরণ।
থ্রিডিউবলুন

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

4
@ কাইফাই: এটি না দেওয়ার জন্য দুঃখিত, তবে এটি "গোপনে রেখেছিলেন" বলা সম্পূর্ণ ভুল, বিশেষত গুগলে যখন এটি "অপরিজ্ঞাত আচরণের" জন্য দ্বিতীয় ফলাফল, যা আমি নির্দিষ্ট শব্দটির জন্য ব্যবহার করছিলাম যা উদ্দীপ্ত হয়েছিল ।
ফিলক্যাব

4

iবাইনারি অঙ্কের একটি নির্দিষ্ট পরিমাণ ব্যবহার করে এর মান মেমোরিতে সংরক্ষণ করা হয়। যখন কোনও সংখ্যাকে উপলব্ধ হওয়ার চেয়ে আরও বেশি সংখ্যার প্রয়োজন হয়, কেবলমাত্র সর্বনিম্ন অঙ্কগুলি সংরক্ষণ করা হয় (সর্বাধিক অঙ্কগুলি হারিয়ে যায়)।

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

এখানে প্রারম্ভিক মানটি 1, সুতরাং আমরা যদি সংরক্ষণের iজন্য 8 সংখ্যা ব্যবহার করি (উদাহরণস্বরূপ),

  • 0 পুনরাবৃত্তির পরে মানটি হয় 00000001
  • 1 পুনরাবৃত্তির পরে, মান হয় 00000010
  • 2 পুনরাবৃত্তির পরে, মান হয় 00000100

চূড়ান্ত অ-শূন্য পদক্ষেপ না হওয়া পর্যন্ত

  • 7 পুনরাবৃত্তির পরে, মান হয় 10000000
  • 8 টি পুনরাবৃত্তির পরে, মান হয় 00000000

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


3

এটি সঠিক, তবে 31 পুনরাবৃত্তির পরে, 1073741824 + 1073741824 সঠিকভাবে গণনা করে না এবং তার পরে কেবল 0 মুদ্রণ করে।

আপনি BigInteger ব্যবহারের জন্য চুল্লি করতে পারেন, তাই আপনার অসীম লুপটি সঠিকভাবে কাজ করবে।

public class Mathz {
    static BigInteger i = new BigInteger("1");

    public static void main(String[] args) {    

        while (true){
            i = i.add(i);
            System.out.println(i);
        }
    }
}

আমি যদি int এর পরিবর্তে দীর্ঘ ব্যবহার করি তবে এটি দীর্ঘ সময়ের জন্য মুদ্রণ> 0 নম্বর বলে মনে হচ্ছে। কেন এটি 63৩ টি পুনরাবৃত্তির পরে এই সমস্যার মধ্যে চলে না?
দেইস

4
"সঠিকভাবে গণনা করা হয় না" এটি একটি ভুল বৈশিষ্ট্য। জাভা স্পেস যা বলেছিল তা হওয়া উচিত অনুসারে গণনা সঠিক। আসল বিষয়টি হ'ল (আদর্শ) গণনার ফলাফলটিকে হিসাবে হিসাবে উপস্থাপন করা যায় না int
স্টিফেন সি

@OOTesterOo - কারণ তুলনামূলক longবেশি সংখ্যক প্রতিনিধিত্ব করতে intপারে।
স্টিফেন সি

দীর্ঘ একটি বৃহত্তর পরিসীমা আছে। BigInteger প্রকারটি আপনার JVM বরাদ্দ করতে পারে এমন কোনও মান / দৈর্ঘ্য গ্রহণ করে।
ব্রুনো ভোলপাটো

আমি ধরে নিয়েছি যে 31 টি পুনরাবৃত্তির পরে ইনটি ওভারফ্লোস কারণ এটি একটি 32-বিট সর্বাধিক আকারের সংখ্যা, এবং এত দীর্ঘ যা কোনও 64-বিট 63 এর পরে তার সর্বোচ্চটি আঘাত করবে? কেন এটা হয় না?
ডিয়ারস

2

এই জাতীয় ক্ষেত্রে ডিবাগিংয়ের জন্য লুপে পুনরাবৃত্তির সংখ্যা হ্রাস করা ভাল। আপনার পরিবর্তে এটি ব্যবহার করুন while(true):

for(int r = 0; r<100; r++)

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


2

আমি উদাহরণের জন্য একটি 8-বিট নম্বর ব্যবহার করব কারণ এটি একটি স্বল্প জায়গায় সম্পূর্ণ বিশদভাবে ব্যাখ্যা করা যেতে পারে। হেক্স সংখ্যা 0x দিয়ে শুরু হয়, বাইনারি সংখ্যা 0 বি দিয়ে শুরু হয়।

8-বিট স্বাক্ষরযুক্ত পূর্ণসংখ্যার সর্বাধিক মান 255 (0xFF বা 0b11111111)। আপনি যদি 1 যুক্ত করেন তবে আপনি সাধারণত: 256 (0x100 বা 0b100000000) পাওয়ার আশা করবেন। তবে যেহেতু এটি প্রচুর পরিমাণে বিট (9), এটি সর্বাধিকেরও বেশি, সুতরাং প্রথম অংশটি আপনাকে 0 কার্যকর (0x (1) 00 বা 0 বি (1) 00000000 রেখে, তবে 1 টি বাদ দিয়ে) ছাড়বে।

সুতরাং যখন আপনার প্রোগ্রাম চলে, আপনি পাবেন:

1 = 0x01 = 0b1
2 = 0x02 = 0b10
4 = 0x04 = 0b100
8 = 0x08 = 0b1000
16 = 0x10 = 0b10000
32 = 0x20 = 0b100000
64 = 0x40 = 0b1000000
128 = 0x80 = 0b10000000
256 = 0x00 = 0b00000000 (wraps to 0)
0 + 0 = 0 = 0x00 = 0b00000000
0 + 0 = 0 = 0x00 = 0b00000000
0 + 0 = 0 = 0x00 = 0b00000000
...

1

টাইপের বৃহত্তম দশমিক আক্ষরিক intহ'ল 2147483648 (= 2 31 )। 0 থেকে 2147483647 পর্যন্ত সমস্ত দশমিক আক্ষরিক কোথাও উপস্থিত হতে পারে যেখানে কোনও অন্তর্গত আক্ষরিক উপস্থিত হতে পারে তবে আক্ষরিক 2147483648 অন্তর্গত কেবল অ্যানারি নেগ্রেশন অপারেটরের অপারেন্ড হিসাবে উপস্থিত হতে পারে -।

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

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