مضروب في ج دون الشرطية والحلقات العوامل الحسابية

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

  •  19-08-2019
  •  | 
  •  

سؤال

كيف يمكنني أن أجد مضروب عدد (من 1 إلى 10) في ج ، دون استخدام:

  • حلقة البيانات مثل ، في حين لا حين ،
  • الشرطي شركات مثل إذا القضية ؛ و
  • العوامل الحسابية مثل + , − , * , % , /, ++, --?

لمعلوماتك:وجدت هذا السؤال في ج الكفاءة.

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

المحلول

نظرًا لأنه يتراوح من 1 إلى 10 فقط، ما عليك سوى حسابه مسبقًا وتخزينه في مصفوفة int بسيطة بحجم 11.للعنصر الأول في المصفوفة ضع 1.إنه ليس نطاق إدخال صالحًا لمشكلتك ولكنه قد يكون صحيحًا أيضًا.

نحتاج إلى تخزين 11 عنصرًا بدلاً من العناصر العشرة التي نحتاجها، وإلا فسنحتاج إلى استخدام العملية "-" للحصول على الفهرس الصحيح.الطرح غير مسموح به في مشكلتك بالرغم من ذلك.

int factorial(int x)
{
  return precomputedArray[x];
}

نصائح أخرى

هنا حل بدون حلقات أو عمليات حسابية أو شرطية ولا يلجأ إلى الحساب المسبق. كما أنه لا يستخدم الشروط الشرطية ذات الدائرة القصيرة مثل && أو || والتي هي في الواقع ما يعادل if. لذا يبدو أن هذا هو الحل الصحيح الأول بدون أي شروط على الإطلاق.الآن في لغة C المناسبة بدون ميزات C++ :)

#include <stdio.h>
#define uint unsigned int

void A(uint *a, uint *b)
{
    uint tmp = *a & *b;
    *a = (*a | *b) & ~tmp;
    *b = tmp << 1;
}

#define REPEAT32(s) \
s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s

uint add(uint a, uint b)
{
    REPEAT32(A(&a, &b);) return a;
}

uint bitexpand(uint b)
{
    b = (b << 1)  | b; b = (b << 2)  | b; b = (b << 4)  | b;
    b = (b << 8)  | b; b = (b << 16) | b;
    return b;
}

void M(uint *acc, uint *a, uint *b)
{
    *acc = add(*acc, *a & bitexpand(*b & 1));
    *a <<= 1;
    *b >>= 1;
}

uint mult(uint a, uint b)
{
    uint acc = 0;
    REPEAT32(M(&acc, &a, &b);) return acc;
}

uint factorial(int n)
{
    uint k = 1;
    uint result = 0;
    result |= (bitexpand(n == 1) & k);
    k = mult(k, 2); result |= (bitexpand(n == 2) & k);
    k = mult(k, 3); result |= (bitexpand(n == 3) & k);
    k = mult(k, 4); result |= (bitexpand(n == 4) & k);
    k = mult(k, 5); result |= (bitexpand(n == 5) & k);
    k = mult(k, 6); result |= (bitexpand(n == 6) & k);
    k = mult(k, 7); result |= (bitexpand(n == 7) & k);
    k = mult(k, 8); result |= (bitexpand(n == 8) & k);
    k = mult(k, 9); result |= (bitexpand(n == 9) & k);
    k = mult(k, 10); result |= (bitexpand(n == 10) & k);
    return result;
}

int main(int argc, char **argv)
{
    uint i;
    /* Demonstration loop, not part of solution */
    for (i = 1; i <= 10; i++)
    {
        printf("%d %d\n", i, factorial(i));
    }
}

محدث:احتوت المناقشة على الادعاء بأن قصر الدائرة الشرطية مثل && سيكون مقبولاً في الحل الذي لا يستخدم if.إليك ماكرو بسيط يحاكي "if" ثنائي الاتجاه باستخدام && ومن الواضح أنه يجعل المشكلة برمتها أقل إثارة للاهتمام:

#define IF(i, t, e) \
(void)((i) && (goto then##__LINE__, 1)); goto else##__LINE__;
then##__LINE__: t; goto cont##__LINE__; \
else##__LINE__: e; cont##__LINE__: ((void)0);

يمكنك بعد ذلك تحديد

#define WHILE(c, s) \
loop##__LINE__: IF(c, s; goto loop##__LINE__, ((void)0)))

ومن ثم تصبح بقية المشكلة تافهة.

#include <stdio.h>

static const int factorial[] = {
    1,
    1,
    2,
    6,
    24,
    120,
    720,
    5040,
    40320,
    362880,
    3628800,
};

/* Test/demo program. */
int main(void)
{
    int i;

    for (i = 0; i <= 10; ++i)
        printf("%d %d\n", i, factorial[i]);

    return 0;
}

(أي شخص يستخدم هذا الجواب عن سؤال في الواجب إما فشل أو المعلم مع شعور جيد من الفكاهة.)

(Bah كنت بطيئة.البعض أعطى الناس هذا الجواب بالفعل.لا تتردد في التصويت الجواب عنه.)

ربما أقوم بحل الواجب المنزلي لشخص ما، لكنه بدا وكأنه تحدٍ ممتع، على أي حال، إليك الحل (مجمع مع التحذيرات، ولكن لا يمكنني مساعدة هؤلاء دون جعله يبدو قبيحًا))

يحرر: لقد قمت بتغيير البرنامج لجعله يدعم مضروبات أطول بكثير (يصل إلى 20 أو نحو ذلك) وجعلت الكود أكثر ترتيبًا عن طريق إزالة جدول البحث بالداخل prev().

#include <stdio.h>
#include <stdlib.h>

#define _if(CND, OP1, OP2) (((CND) && ((OP1) || 1)) || (OP2))

long long int add(long long int x, long long int y){
    long long int r = x ^ y;
    long long int c = x & y;
        c = c << 1;    
    _if(c != 0, r = add(r, c), 1);

    return r;
}

long long int prev(long long int x){
    return add(x, -1);
}                           

long long int mult(long long int x, long long int y){
    long long int r;

    _if(x == 0,
         r = 0,
       _if(x == 1, 
            r = y, 
            r = add(y, mult(prev(x), y))));

    return r;
}

long long int fac(long long int x){
    long long int r;

    _if(x < 2,
        r = 1,
        r = mult(x, fac(prev(x))));

    return r;
}

int main(int argc, char**argv){
    long long int i;

    for(i = 0; i <= 20; i++)
        printf("factorial(%lli) => %lli\n", i, fac(i));

    return 0;
}

تشغيل العينة:

[dsm@localhost:~/code/c]$ gcc -o proc proc.c
[dsm@localhost:~/code/c]$ ./proc #/
factorial(0) => 1
factorial(1) => 1
factorial(2) => 2
factorial(3) => 6
factorial(4) => 24
factorial(5) => 120
factorial(6) => 720
factorial(7) => 5040
factorial(8) => 40320
factorial(9) => 362880
factorial(10) => 3628800
factorial(11) => 39916800
factorial(12) => 479001600
factorial(13) => 6227020800
factorial(14) => 87178291200
factorial(15) => 1307674368000
factorial(16) => 20922789888000
factorial(17) => 355687428096000
factorial(18) => 6402373705728000
factorial(19) => 121645100408832000
factorial(20) => 2432902008176640000
[dsm@localhost:~/code/c]$

"+" و"-" و"*" محظورة بشكل صريح، ولكن "+=" و"-=" و"*=" ليست كذلك وبالتالي يصبح التنفيذ العودي...

int factorial( int arg )
{
    int argcopy = arg;
    argcopy -= 1;
    return arg == 1 ? arg : arg *= factorial( argcopy );
}

يرفض VC7 تجميع ما ورد أعلاه عندما يكون في "الترجمة كوضع مصدر C" - يشتكي من قيمة const L لـ "*="، ولكن هنا متغير آخر لنفس الشيء:

int factorial( int arg )
{
    int argcopy1 = arg;
    int argcopy2 = arg;
    argcopy1 -= 1;
    argcopy2 *= arg == 1 ? 1 : fact( argcopy1 );
    return argcopy2;
}

هذه ليست إجابة كاملة، ولكن مجرد طرق مختلفة ل add() و mult() المهام:

#define add(a, b)  sizeof (struct { char x[a]; char y[b]; })
#define mult(a, b) sizeof (struct { char x[a][b]; })

(أعتقد أن لغة C، على عكس لغة C++، تسمح بتعريف أنواع جديدة داخل ملف sizeof.)

فيما يلي تطبيق آخر (غير قابل للنقل تمامًا) لـ add() على أساس حساب المؤشر:

int add(int x, int y) {
    return (int) &((char*) x)[y];
}

إليكم الحل ( فقط واحد حتى الآن) الذي يحل المشكلة بالفعل في ظل القيود المطلوبة.

int fac( int n )
{
    /* The is the binary representation of the function: */
    /* 0000 => 0000000000000000001 */
    /* 0001 => 0000000000000000001 */
    /* 0010 => 0000000000000000010 */
    /* 0011 => 0000000000000000110 */
    /* 0100 => 0000000000000011000 */
    /* 0101 => 0000000000001111000 */
    /* 0110 => 0000000001011010000 */
    /* 0111 => 0000001001110110000 */
    /* 1000 => 0001001110110000000 */
    /* 1001 => 1011000100110000000 */
    int bit0 = n & 1;
    int bit1 = (n & 2) >> 1;
    int bit2 = (n & 4) >> 2;
    int bit3 = (n & 8) >> 3;
    int notbit0 = bit0 ^ 1;
    int notbit1 = bit1 ^ 1;
    int notbit2 = bit2 ^ 1;
    int notbit3 = bit3 ^ 1;
    return
    (bit0 & notbit1 & notbit2 & bit3) << 18 |
    (bit0 & notbit1 & notbit2 & bit3) << 16 |
    (notbit1 & notbit2 & bit3) << 15 |
    (notbit1 & notbit2 & bit3) << 11 |
    (notbit1 & notbit2 & bit3) << 8 |
    (notbit1 & notbit2 & bit3) << 7 |
    (notbit0 & notbit1 & notbit2 & bit3) << 12 |
    (notbit0 & notbit1 & notbit2 & bit3) << 10 |
    (bit0 & bit1 & bit2 & notbit3) << 12 |
    (bit1 & bit2 & notbit3) << 9 |
    (bit0 & bit1 & bit2 & notbit3) << 8 |
    (bit1 & bit2 & notbit3) << 7 |
    (bit0 & bit2 & notbit3) << 5 |
    (bit2 & notbit3) << 4 |
    (notbit0 & bit1 & bit2 & notbit3) << 6 |
    (bit0 & notbit1 & bit2 & notbit3) << 6 |
    (notbit1 & bit2 & notbit3) << 3 |    
    (bit0 & bit1 & notbit2 & notbit3) << 2 |    
    (bit1 & notbit2 & notbit3) << 1 |    
    (notbit1 & notbit2 & notbit3);
}

هنا برنامج اختبار:

#include <stdio.h>

int main()
{
    int i, expected, j;
    for( i = 0; i < 10; ++i )
    {
        expected = 1;
        for( j = 2; j <= i; ++j )
        {
            expected *= j;
        }
        if( expected != fac( i ) )
        {
            printf( "FAILED: fac(%d) = %d, expected %d\n", i, fac( i ), expected );
        }
    }
}

يستخدم asm لكتابة رمز التجميع.

أو قم بترجمة برنامج مسبقًا وتنفيذه من برنامجك.

لماذا تفرض مثل هذه القيود على الكود الخاص بك؟

هنا حل يستخدم حساب المؤشر للحسابات ومؤشرات الدالة للشروط الشرطية.

#include <stdio.h>

int fact(int n);

int mul(int a, int b)
{
        struct s {
                char _v[b];
        };
        struct s *p = (struct s*)0;
        return (int) &p[a];
}

int add(int a, int b)
{
        return (int) (&((char *)a)[b]);
}

int is_0(int n)
{
        return (n == 0);
}

int fact_0(int n)
{
        return 1;
}

int fact_n(int n)
{
        return mul(n, fact(add(n,-1)));
}

int (*facts[2])(int) = {fact_n, fact_0};

int fact(int n)
{
        return facts[is_0(n)](n);
}

int main(int argc, char **argv)
{
        int i;
        for(i = 0; i<=10; i++) {
                printf("fact %d = %d\n", i, fact(i));
        }
}

تشغيل العينة:

 ~ > gcc -std=c99 fact.c 
 ~ > ./a.out 
fact 0 = 1
fact 1 = 1
fact 2 = 2
fact 3 = 6
fact 4 = 24
fact 5 = 120
fact 6 = 720
fact 7 = 5040
fact 8 = 40320
fact 9 = 362880
fact 10 = 3628800

قم بإنتاج مجموعة عملاقة من العوامل الثلاثية التي تعيد قيمة محسوبة مسبقًا لكل إدخال مسموح به.استخدم وحدات الماكرو لحساب القيم.

حساب المضروب هو المرة الأولى (والأخيرة بالنسبة للعديد من الأشخاص) التي ستستخدم فيها التكرار.التنفيذ القياسي هو

long fact(int x)
{
   if (x < 2)
     return 1L;
   else
     return fact(x - 1) * x;
}

قد يجادل البعض بأن العبارة الأخيرة يجب أن تكون "x * حقيقة (x-1)" حتى يتمكن المترجم من التعرف على أنها عودية ذيلية.أنا شخصياً أشك في أن أي مترجم ذكي بما يكفي لرؤيته بهذا الشكل وعدم رؤيته بالشكل الآخر.

ومع ذلك، نظرًا لأنك قصرت الأمر على عدم استخدام "if" أو "-"، فلا أعرف كيف ستفعل ذلك.

رسم تقريبي (اقترحه الآخرون بالفعل!)

int[] factorials = {1,1,2,6,24, 120,720, ..etc };
return factorials[i];

لقد حاولت أيضًا وضع القيم في المصفوفة.لقد استخدمت هنا الشروط وحلقات while ولكن لم يتم استخدام أي عوامل حسابية.!أحاول إذا كان بإمكاني إزالتها أيضًا.

#include <stdio.h>

int add(int a, int b)
{
int t1, t2, ab, bb, cb=0, orb=1, ans=0;

do {
    t1 = a >> 1; 
    t2 = t1 << 1;

    if (a==t2) ab=0; else ab=1;

    t1 = b >> 1;
    t2 = t1 << 1; 

    if (b==t2) bb=0; else bb=1;

    if (ab==1 && bb==1) { 
        if (cb==1) ans=ans | orb; 
        cb = 1; 
        }

    if ( ab!=bb ) { 
        if (cb==0) ans = ans | orb; 
        }

    if (ab==0 && bb==0) {
        if (cb==1) { 
        ans = ans | orb;
        cb=0;
                }
        }

    orb = orb << 1; 
    a = a >> 1;
    b = b >> 1;

    } while (a!=0 || b!=0);

if (cb==1) ans = ans | orb;

return ans;
}



int multiply(int x,int y)
{
    int result = 0, i = 0 , j=0;

    while((i=add(i,1)) <= y)
        result = add(result,x);

    return result;

}

int factorial(int x)
{
    if(x==1)
        return 1;
    else
        return multiply(x,factorial(x-1));

}


int main()
{
    int x;
    printf("Enter a number between 0 and 10: ");
    scanf("%d" , &x);
    printf("\nFactorial: %d\n" , factorial(x));
    return 0;
}

دعونا نرى ما إذا كان بإمكاننا القيام بشيء نصف أنيق، دون الاعتماد على الآخرين 1 <= ن <= 10.

  • بدلاً من التكرار، سنستخدم بالطبع التكرار.
  • بدلاً من استخدام if لإنهاء العودية، سنستخدم مجموعة من المؤشرات الوظيفية!
    (ما زلنا بحاجة إلى عوامل المقارنة، مثل < و ==.)

يحرر: استخدم دامارو خدعة المؤشرات الوظيفية أولاً.

هذا يعطي:[لم يتم اختبار جميع التعليمات البرمجية، ولا يوجد مترجم C تحت متناول اليد!]

typedef int (*unary_fptr)(int);

int ret_1(int n) {
    return 1;
}

int fact(int n) {
    unary_fptr ret_1_or_fact[] = {ret_1, fact};
    return multiply(ret_1_or_fact[n > 1](sub_1(n)), n);
}

وما زلنا بحاجة إلى التنفيذ sub_1 و multiply.دعنا نبدء ب sub_1, ، وهو تكرار بسيط على البتات حتى يتوقف الحمل (إذا كنت لا تفهم هذا، فإن الشيء المماثل add_1 في النهاية من الأسهل التفكير):

int identity(int n) {
    return n;
}

int sub_1(int n) {
    unary_fptr sub_1_or_identity[] = {sub_1, identity};
    int lsb = n & 1;
    int rest = sub_1_or_identity[lsb](n >> 1);
    return (rest << 1) | (lsb ^ 1);
}

multiply:أبسط ما يمكنني التفكير فيه هو تكاثر الفلاحين الروس, ، مما يقللها إلى التحولات الثنائية والإضافة.مع الشروط الشرطية، تبدو الصيغة العودية كما يلي:

 /* If we could use conditionals */
int multiply(int a, int b) {
    int subproduct;
    if(a <= 1) {
       subproduct = 0;
    } else {
       subproduct = multiply(a >> 1, b << 1);
    }

    if(a & 1) {
       return add(b, subproduct);
    } else {
       return subproduct;
    }
}

بدون الشروط الشرطية، علينا استخدام خدعة مصفوفة الإرسال مرتين:

typedef int (*binary_fptr)(int, int);

int ret_0(int a, int b) {
    return 0;
}

int multiply(int a, int b) {
    binary_fptr ret_0_or_multiply = {ret_0, multiply};
    int subproduct = ret_0_or_multiply[a >= 2](a >> 1, b << 1);

    binary_fptr ret_0_or_add = {ret_0, add};
    return ret_0_or_add[a & 1](subproduct, b);
}

الآن كل ما نفتقده هو add.يجب عليك الآن تخمين كيف ستسير الأمور - عودية متزامنة على أجزاء من الرقمين، مما يقلل المشكلة إلى تحولات و add_1:

int add(int a, int b) {
    int lsb = (a & 1) ^ (b & 1);
    int carry = (a & 1) & (b & 1);

    binary_fptr ret_0_or_add = {ret_0, add};
    int subsum = ret_0_or_add[(a >= 2) & (b >= 2)](a >> 1, b>> 1);

    unary_fptr identity_or_add_1 = {identity, add_1};
    return identity_or_add_1[carry](subsum << 1);
}

و add_1 عبارة عن تكرار بسيط على البتات حتى يتوقف الحمل:

int add_1(int n) {
    unary_fptr identity_or_add_1[] = {identity, add_1};
    int lsb = n & 1;
    int rest = identity_or_add_1[lsb](n >> 1);
    return (rest << 1) | (lsb ^ 1);
}

هذا كل ما أعتقد![كما هو مذكور أعلاه، لم يتم اختبار كل التعليمات البرمجية!]

إذا لم تتمكن من استخدام العودية أو الحساب وكان لديك نطاق محدود من المدخلات، فيمكنك ترميز النتيجة لتكون عبارة عن بحث عن مصفوفة،

لذا:

return factorials[x];

حيث قمت بملءها مسبقًا factorials مع القيم ذات الصلة

ماذا لو كان علينا حساب العوامل من 1 إلى 100.كيفية تخزين هذه الأرقام الكبيرة؟

#include<stdio.h>
void main()
{
    unsigned long int num,fact,counter;
    while(counter<=num)
    {
        printf("Enter the number");
        scanf("%d",&num);
        fact=fact*counter;
        counter++;
        printf("The factorial of number entered is %lu",fact);
    }
    printf("press any key to exit...");
    getch();
}

نظرًا لأنه لم يذكر عدم استخدام وظائف المكتبة:

#include    <stdlib.h>
#include    <stdio.h>
#include    <math.h>

int main( int argc, char** argv)
{
    printf( "%d\n", (int)round( exp( lgamma(2))));
    printf( "%d\n", (int)round( exp( lgamma(3))));
    printf( "%d\n", (int)round( exp( lgamma(4))));
    printf( "%d\n", (int)round( exp( lgamma(5))));
    printf( "%d\n", (int)round( exp( lgamma(6))));
    printf( "%d\n", (int)round( exp( lgamma(7))));
    printf( "%d\n", (int)round( exp( lgamma(8))));
    printf( "%d\n", (int)round( exp( lgamma(9))));
    printf( "%d\n", (int)round( exp( lgamma(10))));
    printf( "%d\n", (int)round( exp( lgamma(11))));

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