• 0
yacinebrca

عمل swap لمتغيرين بدون متغير وسيط

سؤال

السلام عليكم .


 


. :D ..أحواني سأقدم لكم تمرين أخذ من بعض الوقت تمرين بسيط جدا :P ....


 


المشكل يقول ... برنامج يامر المستخدم بادخال قيمتين  مثلا


 


a = 36 ;b = -78


 


 


ثم يقوم البرنامج بقلب القيمتين


 


هكذا... :rolleyes:


 


b = 36 ;a = -78


 


 


.. لكن يمنع :ph34r: اضافة متغير أو دوال مساعدة ...أو التلاعب بprintf. :ph34r: ..


 


 


:huh: :mellow: حظ موفق :o B)


تم تعديل بواسطه مصطفى 36a2
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

23 إجابة على هذا السؤال .

  • 0

توجد أكثر من طريقة ..

 

إذا كانت المتغيرات عددية, نستخدم :

x=x+y;y=x-y;x=x-y;

و إذا كانت y تختلف عن الصفر :

x=x*y;y=x/y;x=x/y;

و توجد أيضاً طريقة ثالثة باستخدام الـ Bitwise :

x = x^yy = x^yx = x^y

بالتوفيق.

1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

و عليكم السلام ورحمة الله و بركاته 

تم حل التمرين يا أستاذ  :lol:

#include<stdio.h>main(){    float a,b;    printf("entrer a : ");    scanf("%f",&a);    printf("entrer b : ");    scanf("%f",&b);    a=a+b;    b=a-b;    a=a-b;    printf("a : %f\n",a);    printf("b : %f",b);}
تم تعديل بواسطه tantie L
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

لكن تبقى طريقة المتغير الاضافي اسرع

 

بدون المتغير الاضافي

void swap(int &x, int &y){  x=x+y;  y=x-y;  x=x-y;}

المقابل بالاسمبلي

__Z4swapRiS_:	pushl	%ebp	movl	%esp, %ebp	movl	8(%ebp), %eax	movl	(%eax), %edx	movl	12(%ebp), %eax	movl	(%eax), %eax	addl	%eax, %edx	movl	8(%ebp), %eax	movl	%edx, (%eax)	movl	8(%ebp), %eax	movl	(%eax), %edx	movl	12(%ebp), %eax	movl	(%eax), %eax	subl	%eax, %edx	movl	12(%ebp), %eax	movl	%edx, (%eax)	movl	8(%ebp), %eax	movl	(%eax), %edx	movl	12(%ebp), %eax	movl	(%eax), %eax	subl	%eax, %edx	movl	8(%ebp), %eax	movl	%edx, (%eax)	popl	%ebp	ret

بستخدام المتغير الاضافي

void swap(int &x, int &y){  int z = x;  x = y;  y = z;}

يقابله بالاسمبلي

__Z4swapRiS_:	pushl	%ebp	movl	%esp, %ebp	subl	$16, %esp	movl	8(%ebp), %eax	movl	(%eax), %eax	movl	%eax, -4(%ebp)	movl	12(%ebp), %eax	movl	(%eax), %edx	movl	8(%ebp), %eax	movl	%edx, (%eax)	movl	12(%ebp), %eax	movl	-4(%ebp), %edx	movl	%edx, (%eax)	leave	ret
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

ماشاء الله ... الكل هنا موفق في حل هذا التمرين ...


 


 


شكرا على التفاعل مع الموضوع ...بارك الله فيكم


 


الحــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــل



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

int main()
{

float X,Y;

printf("Dooner la valeur de X : ");
scanf("%f",&X);

printf("Dooner la valeur de Y : ");
scanf("%f",&Y);

X = X + Y ;
Y = X - Y ;
X = X - Y ;

printf(" \n X = %.4f \t Y = %.4f \n\n",X,Y);

system("PAUSE");
return 0;
}
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

يوجد خطأ بسيط في الحل المقدم من طرف


 


fouad2008


&&


 


tantie L


 


 تم تعريف المتغيرات على type : int ...نفترض أن المستخدم أدخل عددا عشريا ( بالفاصلة )...؟؟؟؟؟؟؟؟؟ :blush: :blush:


 


شكرا على المشاركة


تم تعديل بواسطه yacinebrca
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

@fouad2008

أضف إلى ذلك أن الطريقة الأولى و الثانية قد يتسببان في OverFlow إذا كان جمع العددين أو جداءهما أكبر من القيمة العظمى لأحد المتغيرين.

 

بالمناسبة, من استطاع تبديل محتوى متغيرين مهما كان نوعهما, دون إمكانية حدوث الـ Overflow و لم يستعن بمتغير ثالث سأرفع قبعتي احتراماً له :)

تم تعديل بواسطه Snack3r
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أخي ياسين تم تعديل الكود و شكرا على التنبيه

و يا اخي Snak3r من اي نوع هل تقصد حتى نوع char ايضا؟؟؟؟

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جرب هذا:

#include <algorithm>int main(){    double d1 = 10.0, d2 = -12.0;    std::swap(d1, d2);    int i1 = 10, i2 = -9;    std::swap(i1, i2);    bool b1 = true, b2 = false;    std::swap(b1, b2);}

أيا كانت الوسيلة المتبعه داخل swap فأنا لم أكتبها و أيضا لم استخدم متغير إضافي :D

 

و الله ولي التوفيق

1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

بالفعل كما قال الأخ محمد طريقة XOR تسمح بتفادي overflow وإن كان الأخ [email protected] سيقول

وكيف تريد عمل xor لمتغير من نوع float :)

سأقول له : عن طريق عمل cast إلى int ثم xor ثم إعادة عمل  cast إلى float

D:

 

بالمناسبة , الموضوع مطروح سابقاً

تم تعديل بواسطه مصطفى 36a2
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

بالفعل كما قال الأخ محمد طريقة XOR تسمح بتفادي overflow وإن كان الأخ [email protected] سيقول

سأقول له : عن طريق عمل cast إلى int ثم xor ثم إعادة عمل  cast إلى float

D:

 

بالمناسبة , الموضوع مطروح سابقاً

 

ولكن التحويل من رقم عشري إلى رقمي --> سيتم تجاهل الأرقام بعد الفاصلة (ما الفائدة -_- )

إلا إذا كانت هناك خدعة لم أعلم بها  :rolleyes:

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أيا كانت الوسيلة المتبعه داخل swap فأنا لم أكتبها و أيضا لم استخدم متغير إضافي

 

 

جيد, لكن هدفي من السؤال هو كتابة خوارزمية تعمل بشكل مستقل و لا تعتمد على الامكانيات التي توفرها مكتبة معينة.

 

وإن كان الأخ [email protected] سيقول

 

وكيف تريد عمل xor لمتغير من نوع float

 

 

 

 

لا, كنت أود أن أسأل : كيف ستقوم بعمل xor لمتغير من string مثلا ؟ :D

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

هل يمكن إستخدام eax او ebx او edx او  ecx

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

لا, كنت أود أن أسأل : كيف ستقوم بعمل xor لمتغير من string مثلا ؟

هذه قويّة :)

سأقوم بعمل xor لكل بايت من الـ string الأولى مع الثانية ..

الفكرة بالمجمل أنه مهما كان حجم المتغير سنمر على جميع البايتات الخاصة به ونقوم بعمل xor لها مع البايت المقابل في المتغير الثاني

 

@bahbah


ولكن التحويل من رقم عشري إلى رقمي --> سيتم تجاهل الأرقام بعد الفاصلة (ما الفائدة sleep.png )

إلا إذا كانت هناك خدعة لم أعلم بها

ليست حدعة ولكن قصدت cast للمؤشرات هكذا :

float x=5.5;int y=*(int*)&x;

 

والله ولي التوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أنا لست مبرمج بلغة السي لكن لفت إنتباهي شيء كتبه  الأخ  

Snack3r

 

و توجد أيضاً طريقة ثالثة باستخدام الـ Bitwise :

x = x^yy = x^yx = x^y

لا أعرف مالذي كان يقصده ب ال Bitwise

لكني أعتقد أنه من الأصح

x = x^yy = x^(1/y)x = ln(x)/ln(y)

حيث أن :

(x^y)^(1/y) = xln(x^y) = y*ln(x)
تم تعديل بواسطه kenham
-1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أنا لست مبرمج بلغة السي

ولذلك حدث لديك خلط بِان العملية ^ , فهي عملية xor وليست رفع لقوّة

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

هناك طريقة أخرى، سأبرمجها لاحقاً

لمن أراد التحدي، سأضع الطريقة هنا  B)

 

يمكن أن تستخدم shl أو shr لسحب القيمة من الذاكرة بتا بتا، عن طريق الـ carry flag، إن قمت بالتأكد من أن القيم ستوضع جنباً الى جنب بالذاكرة عن طريق إستخدام pragma pack(1) ففي هذه الحالة التخدي سيكون سهلا، لكن المشكلة ستقع إذا كانت قيم المتغيرات متباعدة بالذاكرة، وهنا تكمن الصعوبة، سيكون من الممتع حل هذا المشكل  :D

 

لايهم هنا أبداً نوع المتغير، مهما كان قم فقط بعمل typecast لمؤشر ثم إستمتع بوجبتك  :P

 

حظاً موفقاً.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

هل يمكنك توضيح أي جزء من السؤال تريد حلّه بطريقة مختلفة ؟

بالمناسبة مهما كان ما تفكر فيه أرغب بتذكيرك أن

shl وshr في C يحددها الـcompiler بأن تكون إزاحة منطقية أو إزاحة حسابية :) لذلك انتبه لذلك

 

بالتوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

@مصطفى

عملية الإزاحة المنطقية هي نفسها الإزاحة الحسابية، ففي النهاية عدد الإزاحات يحدد نوع العملية حسابية * أو /

أرى أن هذا غير ممكن، إضافة كيف يمكنك أن تقرأ محتوى الـ flag

أظن أن هذا مستحيل من الناحية العملية

والله أعلم

-1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

عملية الإزاحة المنطقية هي نفسها الإزاحة الحسابية، ففي النهاية عدد الإزاحات يحدد نوع العملية حسابية * أو /

الإزاحة المنطقية تقوم بتحريك كافة البتات يسارا او يمينا بدون قيود.

الإزاحة الحسابية تأخذ فى الإعتبار بت الإشارة حيث إن كان الرقم سالب و يتم الإزاحة لليمين سيتم نسخ بت الإشارة فى كل البتات بأقصي اليسار.

 

إن قمت بالتأكد من أن القيم ستوضع جنباً الى جنب بالذاكرة عن طريق إستخدام pragma pack(1)

هذا تلميح للمترجم قد يقبله و قد يرفضه فلا تضع أمالك عليه.

 

يمكن أن تستخدم shl أو shr لسحب القيمة من الذاكرة بتا بتا،

هذا أسوء إسلوب لأنه بإفتراض ان لدى نص مكون من مائة كيلو (داخل مصفوفة و ليس مؤشر) و اردت إبدالة مع أخر حينها بدلا من نسخ اجزاء من المصفوفة بمساحة مسجل المعالج (memcpy) سأقوم بإستخدام واحد بت فقط مع العلم ان المعالج سيقوم بالحصول على كافة 32بت.

 

للنسخ أستخدم memcpy او دوال بديلة تعمل بإستخدام vector registers و للتبديل بين قيميتن إستخدم std::swap و مع تفعيل التحسينات ستكون أفضل من الكود الذى ستكتبه بيدك و أسرع إلا لو كان الكود الخاص بك مطابق لها

 

 

و الله ولي التوفيق.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أظن أن هذا مستحيل من الناحية العملية

 

 

 

لاشئ مستحيل عزيزي -_- ، كل ماعليك هو فقط أن تؤمن بأنه ممكن وستراه يتحقق أمام عينيك ..

 

الإزاحة الحسابية تأخذ فى الإعتبار بت الإشارة حيث إن كان الرقم سالب و يتم الإزاحة لليمين سيتم نسخ بت الإشارة فى كل البتات بأقصي اليسار.

 

 

 

ليس صحيحاً 100/100، فـ shr و shl لايكثرتان نهائيان لبت الإشارة، بينما التعليمتان sal و sar هما المخصصتان للإشارة، ولأكون دقيقاً sar فقط هي التي تحافظ على بت الإشارة، يمكنك أن تجرب مثالاً ما وآختبر النتيجة ..

 

 

 

هذا تلميح للمترجم قد يقبله و قد يرفضه فلا تضع أمالك عليه.

 

الأمر يعمل دائما معي في تحديد الـ alignement، أرجو إن كنت تعلم طريقة أفضل أن تخبرني بها، جزاك الله كل خير  :)

 

هذا أسوء إسلوب لأنه بإفتراض ان لد

 

 

 

 

بالتأكيد أسلوب  سئ جيد، فهل حقاً، في برنامج حقيقي تعتقد أنني في برنامج حقيقي سأستخدم هذه الطريقة  :huh: ، بالطبع لا، لكن على حسب ما أذكر فموضوع التحدي كان :

 

 

.. لكن يمنع  :ph34r: اضافة متغير أو دوال مساعدة ...أو التلاعب بprintf.  :ph34r: ..

 

 

يعني عرض لمختلف الخيارات، مهما كانت سيئة، أما لو كان الموضوع حول السرعة، فجوابي سيكون ببساطة إستخدام fastcall__ مع الـ Inline assembly، يالنسبة للمتغيرات العادية، أما بالنسبة للـ Strings فلا أرى ما السبب الذي يدفعك الى تغيير محتويات الذاكرة، إن كنت تستخدم call table أو hash table أو شيئاً آخر فيكفي تغيير الـ pointers، أما إن كنت حقا ترغب في تغيير محتويات الذاكرة، فأفضل ماسأقوم به، سيكون أولا التأكد من الحجم، إعادة حجز الذاكرة في حال كان الحجم مختلفاً، وإن كان حجم النص كبيرا، فسأستخدم thread وأقوم بتحديد الـ affinity، في حال كانت البيئة multiprocessing حتى لايشعر المستخدم بأي تأخير، أو هسة .. هناك العديد من الخيارات الأخرى تجول ببالي الآن لكن أظن فكرتي وصلت  ;)

تم تعديل بواسطه zirek99i
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

كما ذكرت أنا:

الإزاحة المنطقية تقوم بتحريك كافة البتات يسارا او يمينا بدون قيود: هما shr و shl و قد ذكرت انت اسماءهم.

الإزاحة الحسابية تأخذ فى الإعتبار بت الإشارة حيث إن كان الرقم سالب و يتم الإزاحة لليمين سيتم نسخ بت الإشارة فى كل البتات بأقصي اليسار: هما sal و sar و قد حددت انا ان sar ينطبق عليها هذا الكلام بدون ذكر إسمها الذى ذكرته أنت.

 

ليس صحيحاً 100/100

و حيث ان كلامي ينطبق مع كلامك فأنا ارغب فى معرفة ما الغير صحيح فيما ذكرت؟؟

 

الأمر يعمل دائما معي في تحديد الـ alignement،

إذا جربت العمل على MIPS أو غيرها من RISC فستدرك ان حجم الـ type الموجود فى الذاكرة لابد ان يكون من مضاعفات الرقم 4 و المترجم لن يقبل اى packing ليس من مضاعفات هذا الرقم.
 

 

و الله ولي التوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

@C++er

 

أعذرني أخي، فلم أنتبه جيداً  :huh:

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .