و # قضايا السلطة التي تقبل كلا الحجج لتكون بيجينتس
-
27-10-2019 - |
سؤال
أنا حاليا تجريب و#.المقالات الموجودة على الإنترنت مفيدة ، ولكن بصفتي مبرمجا ، أواجه أحيانا مواقف اعتقدت أن حلي سيساعد فيها ، لكنه لم يساعد أو ساعد جزئيا.
حتى بلدي عدم معرفة و # (وعلى الأرجح ، كيف يعمل المترجم) هو على الارجح السبب في أنني فلابيرغاستد تماما في بعض الأحيان.
على سبيل المثال ، كتبت برنامج ج# لتحديد أرقام مثالية.يستخدم الشكل المعروف لإثبات إقليدس ، أنه يمكن تكوين رقم مثالي من أ ميرسين رئيس الوزراء 2ص−1(2ص−1) (أين 2ص-1 هو رئيس الوزراء ، و ص يشار إليه على أنه قوة).
منذ مساعدة و# تنص على أن '* * ' يمكن استخدامها لحساب السلطة ، ولكن يستخدم النقاط العائمة ، حاولت إنشاء وظيفة بسيطة مع مشغل بتشيفت (<<<) (لاحظ أنني قمت بتحرير هذا الرمز للإشارة إلى الحاجة):
let PowBitShift (y:int32) = 1 <<< y;;
ومع ذلك ، عند تشغيل اختبار ، وتبحث عن تحسينات في الأداء ، حاولت أيضا النموذج الذي أتذكر من استخدام ميراندا (لغة البرمجة الوظيفية أيضا) ، والذي يستخدم العودية ونمط المطابق لحساب السلطة.الفائدة الرئيسية هي أنه يمكنني استخدام المتغير y كما عدد صحيح 64 بت ، وهو أمر غير ممكن مع مشغل بتشيفت القياسية.
let rec Pow (x : int64) (y : int64) =
match y with
| 0L -> 1L
| y -> x * Pow x (y - 1L);;
اتضح أن هذه الوظيفة هي في الواقع أسرع ، ولكن لا أستطيع (حتى الآن) فهم السبب.ربما يكون سؤالا أقل فكرية ، لكنني ما زلت فضوليا.
السؤال الثواني ثم سيكون ، أنه عند حساب أرقام مثالية ، واجهت حقيقة أن إنت 64 لا يمكن عرض أرقام كبيرة عبور بعد العثور على 9 بيرفيكتنومبر (الذي يتكون من قوة 31).أحاول معرفة ما إذا كان يمكنك استخدام كائن بيغنتيجر (أو نوع بيغنت) ثم ، ولكن هنا معرفتي و# هو حظر لي قليلا.هل من الممكن إنشاء وظيفة قوية تقبل كلتا الوسيطتين على أنهما كبيرتان?
لدي حاليا هذا:
let rec PowBigInt (x : bigint) (y : bigint) =
match y with
| bigint.Zero -> 1I
| y -> x * Pow x (y - 1I);;
لكنه يلقي خطأ أن بيجينت.لم يتم تعريف الصفر.لذلك أنا أفعل شيئا خاطئا هناك أيضا.0أنا غير مقبول كبديل ، لأنه يعطي هذا الخطأ:
Non-primitive numeric literal constants cannot be used in pattern matches because they
can be mapped to multiple different types through the use of a NumericLiteral module.
Consider using replacing with a variable, and use 'when <variable> = <constant>' at the
end of the match clause.
ولكن نمط المطابق لا يمكن استخدام بيان 'عندما'.هل هناك حل آخر للقيام بذلك?
شكرا مقدما ، ويرجى أن يغفر منصبي الطويل.أنا أحاول فقط للتعبير عن بلدي 'التحديات' واضحة بقدر ما أستطيع.
المحلول
فشلت في فهم لماذا تحتاج y
أن تكون int64
أو أ bigint
.وفقا ل هذا الرابط, ، أكبر رقم ميرسين معروف هو الرقم الذي يحتوي على p = 43112609
, ، أين p
هو في الواقع داخل نطاق int
.
وجود y
كعدد صحيح ، يمكنك استخدام المشغل القياسي pown : ^T -> int -> ^T
بدلا من ذلك لأن:
let Pow (x : int64) y = pown x y
let PowBigInt (x: bigint) y = pown x y
فيما يتعلق بسؤالك عن مطابقة النمط bigint
, ، تشير رسالة الخطأ بوضوح تام إلى أنه يمكنك استخدام مطابقة النمط عبر when
الحرس:
let rec PowBigInt x y =
match y with
| _ when y = 0I -> 1I
| _ -> x * PowBigInt x (y - 1I)
نصائح أخرى
أعتقد أن أسهل طريقة لتحديد PowBigInt
هو استخدام if
بدلا من مطابقة النمط:
let rec PowBigInt (x : bigint) (y : bigint) =
if y = 0I then 1I
else x * PowBigInt x (y - 1I)
المشكلة هي أن bigint.Zero
هي خاصية ثابتة تقوم بإرجاع القيمة ، ولكن يمكن أن تحتوي الأنماط فقط على حرفية (ثابتة)أو أنماط نشطة.لا يمكن أن تحتوي مباشرة على مكالمات الملكية (أو غيرها).ومع ذلك ، يمكنك كتابة قيود إضافية في where
شرط إذا كنت لا تزال تفضل match
:
let rec PowBigInt (x : bigint) (y : bigint) =
match y with
| y when y = bigint.Zero -> 1I
| y -> x * PowBigInt x (y - 1I)
كملاحظة جانبية ، يمكنك على الأرجح جعل الوظيفة أكثر فعالية باستخدام الذيل-العودية (والفكرة هي أنه إذا كانت وظيفة يجعل استدعاء العودية كما آخر شيء ، ثم يمكن تجميعها بشكل أكثر كفاءة):
let PowBigInt (x : bigint) (y : bigint) =
// Recursive helper function that stores the result calculated so far
// in 'acc' and recursively loops until 'y = 0I'
let rec PowBigIntHelper (y : bigint) (acc : bigint) =
if y = 0I then acc
else PowBigIntHelper (y - 1I) (x * acc)
// Start with the given value of 'y' and '1I' as the result so far
PowBigIntHelper y 1I
فيما يتعلق PowBitShift
وظيفة-لست متأكدا لماذا هو أبطأ ، لكنها بالتأكيد لا تفعل ما تحتاجه.يعمل استخدام تبديل البت لتنفيذ الطاقة فقط عندما تكون القاعدة 2.
لست بحاجة إلى إنشاء وظيفة الأسرى. عامل التشغيل (**) لديه حمل زائد لـ bigint -> int -> bigint. يجب أن تكون المعلمة الثانية فقط عددًا صحيحًا ، لكنني لا أعتقد أن هذه مشكلة بالنسبة لحالتك. فقط حاول
Genacodicetagprebigint 10 ** 32 ؛؛
هناك خيار آخر يتمثل في تضمين وظيفتك بحيث تعمل مع جميع الأنواع الرقمية (التي تدعم عوامل التشغيل المطلوبة: رمز الترقيم العام ، رمز الترقيم العام ، رمز الترقيم العام ، ورمز الترقيم العام). Genacodicetagpre
ربما أوصي بجعلها متكررة ، كما اقترح توماس.