কেন এই এলোমেলো মান 50/50 এর পরিবর্তে 25/75 বিতরণ করে?


139

সম্পাদনা: সুতরাং মূলত আমি যা লেখার চেষ্টা করছি তা হল 1 বিট হ্যাশ double

আমি একটি মানচিত্র চাই doubleথেকে trueবা falseএকটি 50/50 সুযোগ। তার জন্য আমি এমন কিছু কোড লিখেছি যা কিছু এলোমেলো সংখ্যা বাছাই করে (যেমন একটি উদাহরণ হিসাবে, আমি নিয়মিতভাবে ডেটাতে এটি ব্যবহার করতে চাই এবং এখনও একটি 50/50 ফলাফল পেতে চাই) , তাদের শেষ বিট এবং বর্ধিততাগুলি yযদি এটি 1 হয় বা nএটি হয় তবে 0।

যাইহোক, এই কোডটি নিয়মিত 25% yএবং 75% ফলাফল করে n। কেন এটি 50/50 নয়? এবং কেন এত অদ্ভুত, তবে সোজা-এগিয়ে (1/3) বিতরণ?

public class DoubleToBoolean {
    @Test
    public void test() {

        int y = 0;
        int n = 0;
        Random r = new Random();
        for (int i = 0; i < 1000000; i++) {
            double randomValue = r.nextDouble();
            long lastBit = Double.doubleToLongBits(randomValue) & 1;
            if (lastBit == 1) {
                y++;
            } else {
                n++;
            }
        }
        System.out.println(y + " " + n);
    }
}

উদাহরণ আউটপুট:

250167 749833

43
"এলসিজির স্বল্প বিটগুলিতে কম এনট্রপি রয়েছে" এর পরিবর্তে উত্তরটি ভাসমান-পয়েন্টের পরিবর্তনের এলোমেলো প্রজন্ম সম্পর্কে আকর্ষণীয় কিছু বলে আশা করছি।
স্নেফটেল

4
আমি খুব কৌতূহলী, "1 বিট হ্যাশ ফর ডাবল" এর উদ্দেশ্য কী? আমি এ জাতীয় প্রয়োজনের কোনও বৈধ প্রয়োগ সম্পর্কে গুরুত্বের সাথে ভাবতে পারি না।
কর্সিকা

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

2
@ করসিকা (মন্তব্যটি দুটি ভাগে ভাগ হয়ে গেছে কারণ এটি অনেক দীর্ঘ) আমরা এর চেয়ে সহজ সরল কিছুতে শুরু করতে পারি doubleValue % 1 > 0.5, তবে এটি খুব মোটা-দাগযুক্ত হবে কারণ এটি কিছু ক্ষেত্রে দৃশ্যমান নিয়মকানুনগুলি প্রবর্তন করতে পারে (সমস্ত মান 1 দৈর্ঘ্যের মধ্যে রয়েছে)। যদি এটি খুব মোটা-দানাদার হয় তবে আমাদের কি আরও ছোট রেঞ্জগুলি চেষ্টা করা উচিত doubleValue % 1e-10 > 0.5e-10? হ্যাঁ ঠিক. আপনি হ্যাশ হিসাবে কেবল সর্বশেষ বিট গ্রহণ করা doubleহয় যখন আপনি অন্তত সম্ভাব্য মডুলো সহ শেষ পর্যন্ত এই পদ্ধতির অনুসরণ করেন তখনই ঘটে।
gvlasov

1
@ কেমোট তখন আপনার কাছে এখনও ভারীভাবে পক্ষপাতদুষ্ট কমপক্ষে একটি গুরুত্বপূর্ণ বিট থাকবে এবং অন্য বিট এটির জন্য ক্ষতিপূরণ দেয় না - আসলে একই কারণে এটি শূন্যের দিকেও পক্ষপাতদুষ্ট (তবে এর চেয়ে কম)) সুতরাং বিতরণ প্রায় 50, 12.5, 25, 12.5 হবে। (lastbit & 3) == 0যদিও এটি হিসাবে বিজোড় কাজ করবে।
হেরোলেড

উত্তর:


165

কারণ নেক্সটডুবাল এটির মতো কাজ করে: ( উত্স )

public double nextDouble()
{
    return (((long) next(26) << 27) + next(27)) / (double) (1L << 53);
}

next(x)xএলোমেলো বিট তোলে ।

এখন কেন এই ব্যাপার? কারণ প্রথম অংশ দ্বারা ভাগ হওয়ার প্রায় অর্ধেক সংখ্যা (বিভাগের আগে) কম 1L << 52, এবং তাই তাদের তাত্পর্য পুরোপুরি পূরণ করতে পারে না এটি 53 টি বিট পূরণ করতে পারে, অর্থাত্ তাত্পর্যটির সর্বনিম্ন তাত্পর্যপূর্ণ বিটটি সর্বদা শূন্য থাকে।


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

মূলত, এর doubleমতো দেখতে: ( উত্স )

ডাবল লেআউট

এই চিত্রটিতে দৃশ্যমান নয় এমন একটি অত্যন্ত গুরুত্বপূর্ণ বিশদটি হ'ল যে সংখ্যাগুলি "নরমালাইজড" 1 হয় যা 53 বিট ভগ্নাংশটি 1 দিয়ে শুরু হয় (এটির মতো এক্সপোঞ্জারটি বেছে নিয়ে), সেই 1 বাদ দেওয়া হয়। এই কারণেই ছবিটি ভগ্নাংশের জন্য 52 বিট দেখায় (তাৎপর্যপূর্ণ) তবে কার্যকরভাবে এতে 53 বিট রয়েছে।

সাধারণীকরণের অর্থ হ'ল যদি nextDouble53 তম বিটের কোডটি সেট করা থাকে তবে সেই বিটটি অন্তর্নিহিত নেতৃস্থানীয় 1 এবং এটি চলে যায় এবং অন্যান্য 52 বিটগুলি ফলাফলের তাৎপর্যে আক্ষরিক অনুলিপি করা হয় double। যদি সেই বিটটি সেট না করা থাকে, এটি সেট না হওয়া অবধি বাকি বিটগুলি অবশ্যই বামে স্থানান্তরিত করতে হবে।

গড়ে, অর্ধেক উত্পন্ন সংখ্যাটি সেই ক্ষেত্রে পড়ে যেখানে মেনানটান্ডটি মোটেও বাম দিকে স্থানান্তরিত হয়নি (এবং প্রায় অর্ধেকের মধ্যে 0 টি তাদের ন্যূনতম তাৎপর্যপূর্ণ বিট হিসাবে 0 থাকে), এবং অন্যান্য অর্ধেকটি কমপক্ষে 1 দ্বারা স্থানান্তরিত হয় (বা কেবল সম্পূর্ণভাবে শূন্য) সুতরাং তাদের সর্বনিম্ন উল্লেখযোগ্য বিট সর্বদা 0 হয়।

1: সর্বদা নয়, স্পষ্টতই এটি শূন্যের জন্য করা যায় না, যার সর্বোচ্চ 1 নেই numbers এই সংখ্যাগুলিকে ডেনরমাল বা অস্বাভাবিক সংখ্যা বলা হয়, উইকিপিডিয়া দেখুন: ডেনারমাল সংখ্যা


16
হুররে! আমি কেবল যা আশা করছিলাম।
স্নেফটেল

3
@ ম্যাট সম্ভবতঃ এটি একটি গতি অপ্টিমাইজেশন। বিকল্পটি হ'ল জ্যামিতিক বিতরণ দিয়ে এক্সপোশনটি তৈরি করা হবে এবং তারপরে আলাদাভাবে ম্যান্টিসা করা হবে।
স্নেফটেল

7
@ ম্যাট: "সেরা" সংজ্ঞায়িত করুন। random.nextDouble()সাধারণত এটির জন্য "সর্বোত্তম" উপায় যা এর উদ্দেশ্যে করা হয় তবে বেশিরভাগ লোকেরা তাদের এলোমেলো দ্বিগুণ থেকে 1-বিট হ্যাশ উত্পাদন করার চেষ্টা করে না। আপনি কি অভিন্ন বিতরণ, ক্রিপ্টানালাইসিসের প্রতিরোধের সন্ধান করছেন বা কী?
স্ট্রিপলিং ওয়ারিয়র

1
এই উত্তরটি সূচিত করে যে ওপি যদি এলোমেলো সংখ্যাটি 2 ^ 53 দ্বারা গুণিত করে ফলাফল প্রাপ্ত পূর্ণসংখ্যাটি অদ্ভুত কিনা তা পরীক্ষা করে দেখানো হত, সেখানে 50/50 বিতরণ করা হত।
ধনী 1

4
@ দি ১১১১ এখানে এখানে বলেছে যে nextঅবশ্যই এটির ফিরতে হবে int, সুতরাং এতে কেবল 32 টি বিট থাকতে পারে
12:58 এ হারোলেড

48

ডক্স থেকে :

নেক্সটডুবল পদ্ধতিটি ক্লাস র্যান্ডম দ্বারা বাস্তবায়িত করা হয়েছে যেমন:

public double nextDouble() {
  return (((long)next(26) << 27) + next(27))
      / (double)(1L << 53);
}

তবে এটি নিম্নোক্ত (জোর দেওয়া খনি) বর্ণনা করে:

[জাভার প্রাথমিক সংস্করণগুলিতে, ফলাফলটি ভুল হিসাবে গণনা করা হয়েছিল:

 return (((long)next(27) << 27) + next(27))
     / (double)(1L << 54);

এটি সমান বলে মনে হতে পারে, যদি না আরও ভাল হয় তবে বাস্তবে এটি ভাসমান-পয়েন্ট সংখ্যাগুলির বৃত্তাকার পক্ষপাতিত্বের কারণে একটি বৃহত্তর অদ্বিতীয়তার পরিচয় দেয়: এটি তাত্পর্যপূর্ণরূপে নিম্ন-অর্ডার বিট 0 হওয়ার সম্ভাবনা থেকে তিনগুণ বেশি ছিল তার চেয়ে বেশি হবে 1 ! অনুশীলনে এই অদ্বিতীয়তাই সম্ভবত খুব বেশি কিছু আসে না, তবে আমরা পরিপূর্ণতার জন্য চেষ্টা করি]]

এই নোটটি জাভা 5 এর পর থেকে কমপক্ষে রয়েছে (জাভা <= 1.4 এর জন্য দস্তাবেজগুলি লগইনওয়ালের পিছনে রয়েছে, চেক করতে খুব অলস)। এটি আকর্ষণীয়, কারণ সমস্যাটি সম্ভবত জাভা 8 তে এখনও উপস্থিত রয়েছে Perhaps সম্ভবত "স্থির" সংস্করণটি কখনও পরীক্ষা করা হয়নি?


4
স্ট্রেঞ্জ। আমি কেবল জাভা 8 এ এটি পুনরুত্পাদন করেছি
আইয়ুব

1
এখন এটি আকর্ষণীয়, কারণ আমি কেবল যুক্তি দিয়েছিলাম যে পক্ষপাতটি এখনও নতুন পদ্ধতিতে প্রযোজ্য। আমি কি ভূল?
23:16

3
@ শরল্ড: না, আমি মনে করি আপনি ঠিকই আছেন এবং যে কেউ এই পক্ষপাতদুটি ঠিক করার চেষ্টা করেছিলেন সে ভুল করে থাকতে পারে।
টমাস

6
জাভা লোকদের ইমেল প্রেরণ করার জন্য @হরোল সময় Time
ড্যানিয়েল

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

33

এই ফলটি আমাকে বিস্মিত করে না যে ভাসমান-পয়েন্ট সংখ্যাগুলি কীভাবে উপস্থাপন করা হয়। ধরা যাক আমাদের কাছে খুব সংক্ষিপ্ত ভাসমান-পয়েন্ট টাইপ ছিল মাত্র 4 বিট নির্ভুলতার সাথে। যদি আমরা 0 এবং 1 এর মধ্যে একটি এলোমেলো সংখ্যা তৈরি করে থাকি, সমানভাবে বিতরণ করা হয় তবে 16 টি মান থাকতে পারে:

0.0000
0.0001
0.0010
0.0011
0.0100
...
0.1110
0.1111

যদি তারা সেইভাবে মেশিনে দেখে, আপনি একটি 50/50 বিতরণ পেতে নিম্ন-আদেশ বিটটি পরীক্ষা করতে পারেন। যাইহোক, আইইইই ফ্লোটগুলি ম্যান্টিসার 2 গুণ শক্তি হিসাবে উপস্থাপিত হয়; ফ্লোটের একটি ক্ষেত্র হ'ল 2 এর পাওয়ার (প্লাস একটি নির্দিষ্ট অফসেট)) 2 এর শক্তি নির্বাচন করা হয়েছে যাতে "ম্যান্টিসা" অংশটি সর্বদা একটি সংখ্যা> = 1.0 এবং <2.0 থাকে। এর অর্থ হ'ল, প্রকৃতপক্ষে, অন্যান্য সংখ্যাগুলি 0.0000এইভাবে উপস্থাপিত হবে:

0.0001 = 2^(-4) x 1.000
0.0010 = 2^(-3) x 1.000
0.0011 = 2^(-3) x 1.100
0.0100 = 2^(-2) x 1.000
... 
0.0111 = 2^(-2) x 1.110
0.1000 = 2^(-1) x 1.000
0.1001 = 2^(-1) x 1.001
...
0.1110 = 2^(-1) x 1.110
0.1111 = 2^(-1) x 1.111

( 1বাইনারি পয়েন্টের আগে একটি অন্তর্নিহিত মান; 32- এবং 64-বিট ভাসমানের জন্য, আসলে এটি ধারণ করার জন্য কোনও বিট বরাদ্দ করা হয় না 1))

তবে উপরের দিকে তাকিয়ে দেখানো উচিত যে, আপনি যদি উপস্থাপনাটিকে বিটগুলিতে রূপান্তর করেন এবং স্বল্প বিটের দিকে তাকান, আপনি সময়টি শূন্য 75% পাবেন। এটি 0.5 (বাইনারি 0.1000) এর চেয়ে কম মানের সকল মানগুলির কারণে , যা তাদের মান্টিসাসকে সরিয়ে নিয়ে যাওয়ার কারণে সম্ভব মানগুলির অর্ধেক হয়, যার ফলে 0 কম থাকে। পরিস্থিতিটি মূলত একইরকম হয় যখন ম্যান্টিসার একটি বিধি হিসাবে 52 বিট থাকে (অন্তর্ভুক্ত 1 সহ নয়) double

(প্রকৃতপক্ষে, @ স্নেফটেল একটি মন্তব্যে প্রস্তাবিত হিসাবে, আমরা জেনারেশনের মাধ্যমে বিতরণে 16 টিরও বেশি সম্ভাব্য মান অন্তর্ভুক্ত করতে পারি :

0.0001000 with probability 1/128
0.0001001 with probability 1/128
...
0.0001111 with probability 1/128
0.001000  with probability 1/64
0.001001  with probability 1/64
...
0.01111   with probability 1/32 
0.1000    with probability 1/16
0.1001    with probability 1/16
...
0.1110    with probability 1/16
0.1111    with probability 1/16

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


5
এলোমেলো বিট / বাইটস / যে কোনও কিছু পেতে ভাসমান পয়েন্ট ব্যবহার করা আমাকে যেভাবেই কমিয়ে দেয়। এমনকি 0 এবং n এর মধ্যে এলোমেলো বিতরণের জন্যও আমাদের কাছে এলোমেলো * এন এর চেয়ে আরও ভাল বিকল্প রয়েছে (আরক 4 ব্র্যান্ডম_ ইউনিফর্ম দেখুন)
মীরাবিলোস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.