سؤال

فترة أعصادي Mersenne المستخدمة في الوحدة النمطية random هو (قيل لي) 2 ** 19937 - 1. كرقم ثنائي ، أي عام 19937 '1 على التوالي (إذا لم أكن مخطئا). بيثون يحولها إلى عشرية جميلة بسرعة:

$ python -m timeit '2**19937'
10000000 loops, best of 3: 0.0271 usec per loop

$ python -m timeit -s 'result = 0' 'result += 2**19937'
100000 loops, best of 3: 2.09 usec per loop

أعتقد أن الإصدار الثاني هو الذي يتطلب التحويل؟

وهذا ليس فقط ثنائي. هذا سريع أيضا. (بدلاً من إظهار الأرقام ، أعرض طول العشري الذي تم تحويله إلى سلسلة):

>>> import math
>>> N = 1000
>>> s = str((int(N*math.e))**(int(N*math.pi)))
>>> len(s)
10787
>>> N = 5000
>>> s = str((int(N*math.e))**(int(N*math.pi)))
>>> len(s)
64921

توقيت:

python -m timeit -s 'import math' -s 'N=1000' 's = str((int(N*math.e))**(int(N*math.pi)))'
10 loops, best of 3: 51.2 msec per loop

والسؤال هو: كيف يتم هذا بالفعل؟

هل أنا فقط ساذج أن أعجب؟ أجد مشهد قشرة الثعبان التي تولد عددًا من 5000 مكان أو نحو ذلك في لحظة مذهلة حقًا.

يحرر:

توقيت إضافي اقترحه dalke و truppo

$ python -m timeit 'x=2' 'x**19937'
1000 loops, best of 3: 230 usec per loop
$ python -m timeit 'x=2' 'int(x**19937)'
1000 loops, best of 3: 232 usec per loop
$ python -m timeit 'x=2' 'str(x**19937)'
100 loops, best of 3: 16.6 msec per loop

$ python -m timeit -s 'result = 0' 'x = 2' 'result += x**19937'
1000 loops, best of 3: 237 usec per loop
$ python -m timeit -s 'result = 0' 'x = 2' 'result += x**19937' 'int(result)'
1000 loops, best of 3: 238 usec per loop
$ python -m timeit -s 'result = 0' 'x = 2' 'result += x**19937' 'str(result)'
100 loops, best of 3: 16.6 msec per loop

لذلك يبدو لي مثل result = 0; result += 2**19937 ربما يفرض التحويل.

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

المحلول

بيثون يحولها إلى عشرية جميلة مرتق.

لا أعرف بيثون ، لكن لا ، لا يحتاج إلى القيام بذلك. 2^19937 لا تحتاج إلى حسابات ، إنه مجرد تحول ثنائي ("<<") مع 19937 ، لذلك فهو سريع للغاية. فقط إذا قمت بطباعة ذلك في العشرية ، يكون التحويل الفعلي ضروريًا وهذا أبطأ بكثير.

تحرير: يمكن أن يكون الأساسي هو نفسه التحول (= نقل النقطة) إذا كانت قاعدة الأرقام مطابقة لقاعدة الأسعار.

10^-1 = 0.1 10^0 = 1
10^1 = 10
10^2 = 100
10^3 = 1000
10^n = 1 (N Zeroes)

ترى هذا الأسعار من 10 مع الأسس N ببساطة تحول الرقم. تستخدم أجهزة الكمبيوتر الآن في الغالب القاعدة الداخلية 2 (بت) ، لذا فإن حساب 2^19937 هو وضع بعض الشيء في الموضع 19937 (عد مواقع بت من الصفر).
كمعلومات إضافية: يتم تنفيذ التحويل إلى العشري عادةً بواسطة خوارزمية قهر وإقامة تقسم الرقم على التوالي على قوى Ten. كما ترى ، فإن التحويل الفعلي أبطأ بعامل نصف مليون.

المثال الثاني أكثر إثارة للاهتمام: نظرًا لأنك تقوم بحساب M^n مع الأعداد الصحيحة الكبيرة M ، فإن أسرع طريقة هي مضاعفةها على التوالي وتخزين النتائج المؤقتة.

مثال: 10^345

أ = 10^2
ب = أأ = 10^4
ج = ب
ب = 10^16
D = C*C = 10^256

النتيجة = دججججججججبب*10

(يمكن تحسينها: انظر Knuth ، الخوارزميات الناتجة)

لذلك تحتاج فقط إلى مضاعفات طويلة ويمكن حسابها بشكل فعال.

تحرير: يعتمد التنفيذ الدقيق للضرب: إلى جانب مضاعفة مضاعفة المدرسة العادية ، يتم استخدام تكاثر Karatsuba و Tom-Cooke و Schoenhagen-Strasse (FFT).

نصائح أخرى

أكره أن تمطر على موكبك ، ولكن السبب في ذلك هو أن وحدة الرياضيات لم يتم تنفيذها بالفعل في بيثون.

يدعم Python تحميل المكتبات المشتركة التي تصدر واجهات برمجة تطبيقات Python ، ولكن يتم تنفيذها بلغات أخرى. Math.so ، والتي توفر الوحدة التي تحصل عليها import math, ، يحدث ليكون واحد من هؤلاء (وكذلك هو _random.so).

عند تجميع رمز البايت ، تعبيرات مستمرة مثل 2**19937 سيتم تحسينه إلى ثابت واحد:

>>> def foo(): return 2**10
... 
>>> import dis
>>> dis.dis(foo)
  1           0 LOAD_CONST               3 (1024)
              3 RETURN_VALUE        
>>> 

النظر بدلا من ذلك:

[~] python -m timeit 'x=2' 'x**19937'
1000 loops, best of 3: 210 usec per loop

لا أعرف شيئًا عن أي شيء عن كيفية هذا في الحقيقة تم تنفيذه في Python ، ولكن بالنظر إلى أن هذا هو الضرب البدائي واللوغاريتمات بشكل أساسي ، لست مندهشًا بشكل رهيب أنه سريع بشكل معقول حتى على أعداد كبيرة جدًا.

هناك مكتبات رياضيات دقة تعسفية مثل GMP تنفذ مجموعة واسعة من العمليات بطريقة فعالة للغاية ، تم تحسينها في التجميع ، لهذا الغرض فقط.

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