هل يمكن أن يعود Random.Randint (1،10) من أي وقت مضى 11؟

StackOverflow https://stackoverflow.com/questions/3037952

  •  27-09-2019
  •  | 
  •  

سؤال

عند البحث عن هذا السؤال وقراءة رمز العجين في random.py, ، بدأت أتساءل عما إذا كان randrange و randint تتصرف حقًا كـ "معلن". أنا أميل كثيرًا إلى تصديق ذلك ، لكن الطريقة التي قرأتها ، randrange يتم تنفيذها بشكل أساسي

start + int(random.random()*(stop-start))

(بافتراض قيم عدد صحيح ل start و stop)، لذا randrange(1, 10) يجب إعادة رقم عشوائي بين 1 و 9.

randint(start, stop) يدعو randrange(start, stop+1), ، وبالتالي إعادة رقم بين 1 و 10.

سؤالي الآن:

إذا random() كان من أي وقت مضى للعودة 1.0, ، ومن بعد randint(1,10) سيعود 11, ، أليس كذلك؟

هل كانت مفيدة؟

المحلول

من random.py والمستندات:

"""Get the next random number in the range [0.0, 1.0)."""

ال ) يشير إلى أن الفاصل الزمني حصرية 1.0. هذا هو ، لن يعود 1.0.

هذه اتفاقية عامة في الرياضيات ، [ و ] شامل ، بينما ( و ) حصري ، ويمكن خلط نوعين من الأقواس (a, b] أو [a, b). القي نظرة على ويكيبيديا: الفاصل الزمني (الرياضيات) للحصول على شرح رسمي.

نصائح أخرى

أشارت إجابات أخرى إلى أن نتيجة random() دائما بشكل صارم أقل من 1.0; ؛ ومع ذلك ، هذا فقط نصف القصة.

إذا كنت تحوس randrange(n) كما int(random() * n), ، أنت ايضا بحاجة إلى معرفة ذلك لأي تعويم بيثون x مرضيه 0.0 <= x < 1.0, وأي عدد صحيح إيجابي n, هذا صحيح 0.0 <= x * n < n, ، لهذا السبب int(x * n) هو أقل بدقة من n.

هناك شيئان قد يحدثان خطأ هنا: أولاً ، عندما نحسب x * n, n يتم تحويله ضمنيًا إلى تعويم. إلى حد كبير بما فيه الكفاية n, ، هذا التحويل قد يغير القيمة. ولكن إذا نظرت إلى مصدر Python ، فسترى أنه يستخدم فقط int(random() * n) طريقة ل n اصغر من 2**53 (هنا وأسفل أفترض أن النظام الأساسي يستخدم IEEE 754 الزوجي) ، وهو النطاق الذي يحوله تحويله n إلى تعويم ضمان عدم فقدان المعلومات (لأن n يمكن تمثيلها بالضبط على أنها تعويم).

الشيء الثاني الذي قد يحدث خطأ هو أن نتيجة الضرب x * n (التي يتم تنفيذها الآن كمنتج للعوامات ، تذكر) ربما لن يكون ممثلًا تمامًا ، لذلك سيكون هناك بعض التقريب. إذا x قريب بما فيه الكفاية 1.0, ، من المتصور أن الدائرية ستدور حول النتيجة n بحد ذاتها.

لنرى أن هذا لا يمكن أن يحدث ، نحتاج فقط إلى النظر في أكبر قيمة ممكنة x, ، وهو (على جميع الآلات تقريبًا التي يديرها بيثون) 1 - 2**-53. لذلك نحن بحاجة إلى إظهار ذلك (1 - 2**-53) * n < n لعدد عدد صحيح لدينا n, ، لأنه سيكون صحيحًا دائمًا random() * n <= (1 - 2**-53) * n.

دليل - إثبات (رسم) دع k كن صحيحًا فريدًا k مثل ذلك 2**(k-1) < n <= 2**k. ثم تطفو التالي لأسفل من n هو n - 2**(k-53). نحن بحاجة إلى إظهار ذلك n*(1-2**53) (أي ، القيمة الفعلية ، غير الجذابة ، أقرب إلى المنتج) n - 2**(k-53) من ل n, ، بحيث يتم تقريبها. لكن القليل من الحساب يظهر أن المسافة من n*(1-2**-53) إلى n هو 2**-53 * n, ، بينما المسافة من n*(1-2**-53) إلى n - 2**(k-53) هو (2**k - n) * 2**-53. ولكن 2**k - n < n (لأننا اخترنا k لهذا السبب. 2**(k-1) < n) ، إذن المنتج هو أقرب الى n - 2**(k-53), ، لذلك إرادة الحصول على تقريب لأسفل (على افتراض ، أن المنصة تقوم ببعض أشكال الجولة إلى الخارق).

لذلك نحن آمنون. فوز!


Addendum (2015-07-04): ما سبق يفترض IEEE 754 Binary64 الحساب ، مع وضع التقريب المستدير إلى التعادل. على العديد من الآلات ، هذا الافتراض آمن إلى حد ما. ومع ذلك ، على أجهزة X86 التي تستخدم X87 FPU للنقطة العائمة (على سبيل المثال ، نكهات مختلفة من Linux 32 بت) ، هناك إمكانية لذلك تقريب مزدوج في الضرب ، وهذا يجعل من الممكن random() * n لجولة فوق إلى n في الحالة حيث random() إرجاع أكبر قيمة ممكنة. أصغر مثل n الذي يمكن أن يحدث هذا هو n = 2049. انظر المناقشة في http://bugs.python.org/issue24546 للمزيد من.

من وثائق بيثون:

تعتمد جميع وظائف الوحدة النمطية تقريبًا على الوظيفة الأساسية العشوائية () ، والتي تولد تعويمًا عشوائيًا بشكل موحد في نطاق شبه مفتوح [0.0 ، 1.0).

مثل تقريبا كل prng من أرقام التعويم ..

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top