و # قضايا السلطة التي تقبل كلا الحجج لتكون بيجينتس

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

سؤال

أنا حاليا تجريب و#.المقالات الموجودة على الإنترنت مفيدة ، ولكن بصفتي مبرمجا ، أواجه أحيانا مواقف اعتقدت أن حلي سيساعد فيها ، لكنه لم يساعد أو ساعد جزئيا.

حتى بلدي عدم معرفة و # (وعلى الأرجح ، كيف يعمل المترجم) هو على الارجح السبب في أنني فلابيرغاستد تماما في بعض الأحيان.

على سبيل المثال ، كتبت برنامج ج# لتحديد أرقام مثالية.يستخدم الشكل المعروف لإثبات إقليدس ، أنه يمكن تكوين رقم مثالي من أ ميرسين رئيس الوزراء 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. يجب أن تكون المعلمة الثانية فقط عددًا صحيحًا ، لكنني لا أعتقد أن هذه مشكلة بالنسبة لحالتك. فقط حاول

bigint 10 ** 32 ؛؛

Genacodicetagpre

هناك خيار آخر يتمثل في تضمين وظيفتك بحيث تعمل مع جميع الأنواع الرقمية (التي تدعم عوامل التشغيل المطلوبة: رمز الترقيم العام ، رمز الترقيم العام ، رمز الترقيم العام ، ورمز الترقيم العام). Genacodicetagpre

ربما أوصي بجعلها متكررة ، كما اقترح توماس.

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