الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

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

بدأه yacinebrca في 27 ديسمبر 2013 · 23 رد · 10,320 مشاهدة · في لغة C و ++C
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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


 


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


 


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


 


a = 36 ;b = -78


 


 


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


 


هكذا... :rolleyes:


 


b = 36 ;a = -78


 


 


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


 


 


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


تم تعديل هذه المشاركة بواسطة مصطفى 36a2 في 7 مارس 2014 في 15:31

elearning_image.jpg

#2

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

 

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

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
#3

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

تم حل التمرين يا أستاذ  :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 في 28 ديسمبر 2013 في 01:26

1

ابتسم للدنيا تبتسم لك و افعل الخير و انساه و لا تنسى أي أمر سيء قمت به حتى لا تكرره


لا تنسونا من صالح دعائكم أعانكم الله و ثبتكم على سواء السبيل


:)  :lol:  ^_^ 

#4

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

 

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

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
#5

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


 


 


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


 


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


#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;

}

elearning_image.jpg

#6

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


 


fouad2008


&&


 


tantie L


 


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


 


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


تم تعديل هذه المشاركة بواسطة yacinebrca في 27 ديسمبر 2013 في 22:32

elearning_image.jpg

#7

@fouad2008

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

 

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

تم تعديل هذه المشاركة بواسطة Snack3r في 27 ديسمبر 2013 في 22:59

#8

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

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

ابتسم للدنيا تبتسم لك و افعل الخير و انساه و لا تنسى أي أمر سيء قمت به حتى لا تكرره


لا تنسونا من صالح دعائكم أعانكم الله و ثبتكم على سواء السبيل


:)  :lol:  ^_^ 

#9

جرب هذا:

#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

مدونتي: C++ Tips and Tricks

#10

هل تنفع الـ XOR_swap_algorithm لحل مشكلة الـ overflow؟

Everything will be fine when we TALK LESS, DO MORE


#11

بالفعل كما قال الأخ محمد طريقة XOR تسمح بتفادي overflow وإن كان الأخ Sn@cker سيقول

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

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

D:

 

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

تم تعديل هذه المشاركة بواسطة مصطفى 36a2 في 28 ديسمبر 2013 في 10:01

#12
مصطفى 36a2 كتب:

بالفعل كما قال الأخ محمد طريقة XOR تسمح بتفادي overflow وإن كان الأخ Sn@cker سيقول

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

D:

 

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

 

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

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

رجعت ومازال الفريق خاملاَ  :( 


 


abPuw.1.gif

#13
اقتباس

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

 

 

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

 

اقتباس

وإن كان الأخ Sn@cker سيقول

 

اقتباس
وكيف تريد عمل xor لمتغير من نوع float

 

 

 

 

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

#14

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

#15
اقتباس

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

هذه قويّة :)

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

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

 

@bahbah

اقتباس

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

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

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

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

 

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

#16

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

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 في 19 يناير 2014 في 02:29

−1
#17
اقتباس

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

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

#18

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

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

 

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

 

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

 

حظاً موفقاً.

#19

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

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

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

 

بالتوفيق

#20

@مصطفى

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

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

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

والله أعلم

−1
#21
اقتباس

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

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

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

 

اقتباس

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

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

 

اقتباس

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

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

 

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

 

 

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

مدونتي: C++ Tips and Tricks

#22
اقتباس

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

 

 

 

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

 

اقتباس

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

 

 

 

ليس صحيحاً 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 في 21 يناير 2014 في 17:40

#23

كما ذكرت أنا:

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

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

 

اقتباس
ليس صحيحاً 100/100

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

 

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

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

 

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

مدونتي: C++ Tips and Tricks

#24

@C++er

 

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

مواضيع مشابهة