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

مشكل في حساب وقت التنفيذ

بدأه ابن ابي سفيان في 30 مايو 2012 · 10 رد · 2,037 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

إليكم هذا الكود

#include <iostream>
#include <conio.h>
#include <string.h>
#include <math.h>
#include <time.h>

using namespace std;

clock_t test(int n){
    int i = 0;
    clock_t sr,sp,res;
    sr = clock();
    while(i < n){
        i++;
    }
    sp = clock();
    res = (double)sp-sr/CLOCKS_PER_SEC;
    return res;
};


int main(){
    clock_t t1,t2,t3;
    t1 = test(10000000);
    t2 = test(1000);
    cout
    <<"T1 = "<<t1<<endl
    <<"T2 = "<<t2<<endl;
}

نتيجة هذا الكود هي

T1 = 62
T2 = 62

المشكل هنا أن العملية الأولى تقوم بعمل أكثر من الثانية لكن نلاحظ هنا أن الوقت متطابق

فما الحل لهذا المشكل ؟ ولكم الشكر مسبقا.

نحن قوم أعزنا الله بالإسلام فإن ارتضينا العزة بغيره أذلنا الله

عمر بن الخطاب رضي الله عنه وأرضاه

#2

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

for(int i = 0 ; i<=n;i++)
for(j=0; j<=n; j++)
.
..
.

وانظر اذا اصبح هناك فرق، حاول ان تزيد من عدد حلقات التكرار لترى اذا ماكان هناك فرق

تم تعديل هذه المشاركة بواسطة mental-driller في 30 مايو 2012 في 20:56

No intellectual battle was ever won through retreat
You do not watch Gintama? Dude, you are missing a lot!


صورةmsrgb1485.gif ocajavase7programmerclr.gif

#3

شكرا لك أخي mental-driller

في الحقيقة وضعت الكود السابق لتوضيح الفكرة فقط

جربت هذه الطريقة في مشروع التخرج الخاص بي وكان فيه دالتان مختلفتان بهما ثلاث أو أربع حلقات متداخلة

وقمت بوضع نفس الطريقة السابقة للمقارنة بينهما

لكن النتيجة متطابقة

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

على حد علمي النتيجة السابقة بالميلي ثانية ms

نحن قوم أعزنا الله بالإسلام فإن ارتضينا العزة بغيره أذلنا الله

عمر بن الخطاب رضي الله عنه وأرضاه

#4

للتوضيح أكثر قمت بتعديل الكود السابق

نتيجة الكود التالي

#include <iostream>
#include <conio.h>
#include <string.h>
#include <math.h>
#include <time.h>

using namespace std;

clock_t test(int n){
    int i,j;
    i = 0;
    clock_t sr,sp,res;
    sr = clock();
    while(i < n){
        j = 0;
        while(j < n){
            j++;
        }
        i++;
    }
    sp = clock();
    res = (double)sp-sr/CLOCKS_PER_SEC;
    return res;
};


int main(){
    clock_t t1,t2,t3;
    t1 = test(1000);
    t2 = test(100);
    cout
    <<"T1 = "<<t1<<endl
    <<"T2 = "<<t2<<endl;
}

هي

T1 = 15
T2 = 15

وعندما أعدل القيم التي داخل الدالة إلى

t1 = test(10000);
    t2 = test(100);

فتكون النتيجة

T1 = 234
T2 = 234

كما تلاحظون أنا عدلت في T1 ولكني لم أعدل في T2 ومع ذلك النتيجتان منتطابقتان ؟؟؟؟؟؟؟؟!!!!!!!!!!!!

نحن قوم أعزنا الله بالإسلام فإن ارتضينا العزة بغيره أذلنا الله

عمر بن الخطاب رضي الله عنه وأرضاه

#5

أخى الفكرة ببساطة هى: الدالة clock ترجع الوقت المستغرق منذ بداية البرنامج.

  1. استدعاء دالة برنامجك التى تود اختبارها.
  2. استدعاء دالة clock ترجع الوقت الذى استغرقة البرنامج لكى يعمل حتى الآن ...
  3. استدعاء داالة اخرى ببرنامجك
  4. استدعاء دالة clock - خطوة 2
  5. وهكذا

لا تدرج clock داخل الكود الذى تود اختبارة هذا غير منطقى

أنظر المثال التالى

/* 
 * File:   main.cpp
 * Author: Mohammed Abu Zayed
 * * Created on May 20, 2012, 9:05 PM
 */
#include <iostream>
//#include <conio.h>
#include <string.h>
#include <math.h>
#include <ctime> 

using namespace std;

void test(int n)
{
    int i = 0;
    while (i < n)
        sqrt(i++);
    ////    sp = clock();
    ////    res = (double)sp-sr/CLOCKS_PER_SEC;
    ////    return res;
};

int main()
{
    clock_t t1 = 0, t2 = 0, t3 = 0, t4 = 0;

    test(10000000);
    t1 = clock();
    cout << "T1 = " << static_cast<float> (t1) / CLOCKS_PER_SEC <<" Seconds" <<endl;

    test(100000000);
    t2 = clock()-t1;
    cout << "T2 = " << static_cast<float> (t2) / CLOCKS_PER_SEC <<" Seconds" <<endl;
}

المخرجات:

T1 = 0.4 Seconds
T2 = 3.92 Seconds

والله من وراء القصد:

post-15367-027053900%201340345097.gifpost-15367-087183200%201340344597.gif
post-247365-0-10080400-1379403554_thumb.

#6

بارك الله فيك أخي

لكن ماذا أفعل إذا كان لدي كود في بداية البرنامج لا أريد أن أدخله في حساب الوقت

وقد عدلت الكود السابق لكن لم ينجح

#include <iostream>
#include <conio.h>
#include <string.h>
#include <math.h>
#include <time.h>

using namespace std;

void test(int n){
    int i,j;
    i = 0;
    while(i < n){
        j = 0;
        while(j < n){
            j++;
        }
        i++;
    }
};


int main(){
    clock_t t1 = 0,t2 = 0,t3 = 0;
    // لنفرض أن لدي هنا كود لا أريد أن أدخله في الوقت	
    t1 = clock();
    test(10000);
    t2 = clock();
    test(100);
    t3 = clock();
    cout
    <<"T1 = "<<static_cast<float> (t2 - t1) / CLOCKS_PER_SEC<<endl
    <<"T2 = "<<static_cast<float> (t3 - t2) / CLOCKS_PER_SEC<<endl;
}

ناتج الكود السابق هو

T1 = 0.328
T2 = 0

حسن حسن لقد نجح معي بارك الله فيك أخي AudaNix

نحن قوم أعزنا الله بالإسلام فإن ارتضينا العزة بغيره أذلنا الله

عمر بن الخطاب رضي الله عنه وأرضاه

#7
ابن ابي سفيان كتب:

بارك الله فيك أخي

لكن ماذا أفعل إذا كان لدي كود في بداية البرنامج لا أريد أن أدخله في حساب الوقت

قارن واستنتج:

int main()
{
    clock_t t1 = 0, t2 = 0, t3 = 0, t4 = 0;
    for(int x=0;x <1000000; x++)
        sqrt((double)x);

    t3 = clock();
    test(10000000);
    t1 = clock()-t3;
    cout << "T1 = " << static_cast<float> (t1) / CLOCKS_PER_SEC <<" Seconds" <<endl;

    test(100000000);
    t2 = clock()-t1-t3;
    cout << "T2 = " << static_cast<float> (t2) / CLOCKS_PER_SEC <<" Seconds" <<endl;
}

والله من وراء القصد

post-15367-027053900%201340345097.gifpost-15367-087183200%201340344597.gif
post-247365-0-10080400-1379403554_thumb.

#8

السلام عليكم

هناك دوال API تمكننا من الحصول على فترات توقيت أقل من 1 ميلي ثانية، لكن ولسوء الحظ فإن هذه الدوال تعتمد بشكل كامل على النظام و خصوصا المعالج المركزي. يجب أن يدعم النظام ما يسمى بــ عداد الأداء عالي الدقة (High Resolution Performance Counter) حيث تعتمد دقة هذا العداد على المعالج المركزي.

توجد دالتان من دوال API تستخدمان لهذا الغرض :

الدالة الأولى هي QueryPerformanceFrequency حيث تعطينا تردد العداد أو لنقل عدد الدورات في الثانية الواحدة و تعيد صفراً إذا كان النظام لا يدعم العداد العالي الدقة. أما الدالة الثانية فهي QueryPerformanceCounter التي تعيد القيمة الحالية للعداد.

بهذا يمكننا تقييم المدة التي يأخذها تنفيذ جزء معين من الكود و ذلك باستدعاء الدالة QueryPerformanceCounter مباشرة قبل الجزء الذي نريد تقييم مدته الزمنية ثم استدعائها مرة أخرى مباشرة بعده، ثم نحسب الفرق و نقسمه على التردد فنحصل على الوقت الذي استغرقه تنفيذ ذلك الجزء من الكود.

نفرض مثلاً أن التردد كان 50000 دورة في الثانية، و أن القيمة التي حصلنا عليها قبل الكود هي 1500 و القيمة بعد الكود هي 3500, الفرق هو 2000، و بالقسمة على 50000 نحصل على 0.04 ثانية.

post-219439-057058600%201329728646.png

يمكنك أيضا استخدام timeGetTime أو GetTickCount إذا أردت معرفة التوقيت بدقة أقل. يمكنك بهذه الإجراءات قياس الفروق الزمنية بدقة ميللي ثانية واحدة على الأكثر، وهذه الدقة قد تكون كافية لقياس عمل الخوارزمية التي نتحدث عنها. بهذه الطريقة ستريح نفسك من الصداع الذي تسببه لك المؤقتات الأخرى مثل QPC و RDTSC.

المؤقت QPC يستخدم ما يحلو له في الجهاز ليقدم أكبر دقة ممكنة. قد يعتمد في بعض الأجهزة على تعليمات مباشرة للـــ BIOS ، وفي بعض الحالات قد يقرأ القيم من أماكن أخرى غريبة. لذا ليست له وحدة ثابتة تستطيع استخدامها، فعندما تنادي الدالة

QueryPerformanceCounter ستستقبل قيمة .. الله أعلم ماذا تعني !! قد تكون الدورة هي معدل نبض ساعة المعالج Processor Clock وقد تعني أي شيء آخر. لذلك أنت بحاجة إلى شيء ما يساعدك على تحويل هذه القيمة إلى وحدة زمنية كالثواني, وهنا تأتي الإجراء فائدة الدالة QueryPerformenceFrequency حيث تعيد عدد "الوحدات" في الثانية الواحدة.

مثلاً : أعطتنا QueryPerformanceFrequency القيمة 15000000 (15 مليون وحدة في الثانية)، وسنسميها التردد. وقمنا باستدعاء QueryPerformanceCounter مرتين على فترتين متباعدتين وطرحنا الفرق لنحصل على 45000000.

الآن يمكننا أن نقسم هذه القيمة على التردد لنحصل على 3 ثواني. وهذا هو مبدأ عمل المؤقت QPC الذي تصل دقته إلى النانوثانية، ويستخدم في تزمين الصوت مع الصورة في مشغلات الأفلام كما يُستخدم في قياس الزمن المستغرق لتنفيذ الإجراءات السريعة في ++C.

إلا أن هناك بعض الأمور التي تمنع QPC من أن يكون مؤقتاً مثاليا, تتخلص هذه الأمور في شيئين : تعدد المعالجات، والمعالجات التي تغير سرعتها بشكل مستمر.

في حالة تعدد المعالجات، لو اعتمد QPC على عداد التعليمات في المعالج (وهي الحالة الأكثر شيوعاً) فإنك قد تحصل على نتائج غريبة بين النداءات المختلفة للإجراء، وذلك بحسب أي المعالجات قام بتنفيذ الطلب. فمثلاً المعالج الأول أنجز مئة مليون تعليمة حتى الآن، بينما الثاني أنجز 90 مليون تعليمة فقط، ولذلك فقد تحصل أحياناً على نتائج مضحكة ! كأن يعود الزمن إلى الوراء ( يكون الفرق سالبا ) أو يقفز قفزات كبيرة مفاجئة للأمام.

في الحالة الثانية فإن بعض المعالجات تغير سرعتها بشكل مستمر على حسب الطاقة المتوفرة، وهذه المعالجات تتواجد بشكل رئيسي في الأجهزة المحمولة laptops حيث يخفف المعالج من سرعته عندما يدخل في نظام توفير طاقة البطارية.. وهنا فإن قيمة التردد التي حسبناها مسبقاً تصبح خاطئة لأن التردد قد تغير ويجب قراءته مرة أخرى ...!

هذه الفقرة أخذتها لك من مقالة كتبتها سابقا بعنوان خوارزميات البحث و الترتيب (الجزء الأول)

أرجو لك التوفيق.

1
#9
اقتباس
هناك دوال API تمكننا من الحصول على فترات توقيت أقل من 1 ميلي ثانية، لكن ولسوء الحظ فإن هذه الدوال تعتمد بشكل كامل على النظام و خصوصا المعالج المركزي. يجب أن يدعم النظام ما يسمى بــ عداد الأداء عالي الدقة (High Resolution Performance Counter) حيث تعتمد دقة هذا العداد على المعالج المركزي.

ما شاء الله رائع

لو فكرنا فى حل بأستخدام API يبقى خرجنا من سي++ القياسية ودخلنا على اقسام خاصة بتقديم حلول مخصصة لنظام تشغيل محدد سواء ويندوز او لينكس ولها اقسامهما المخصصة بالمنتدى

1

post-15367-027053900%201340345097.gifpost-15367-087183200%201340344597.gif
post-247365-0-10080400-1379403554_thumb.

#10
اقتباس
لو فكرنا فى حل بأستخدام API يبقى خرجنا من سي++ القياسية ودخلنا على اقسام خاصة بتقديم حلول مخصصة لنظام تشغيل محدد سواء ويندوز او لينكس

لا أظن أنه توجد آلية محددة أو مكتبة جاهزة لحساب الوقت في النسخة القياسية من سي++, لكن يمكن :

  • استخدام الدوال و التراكيب الموجودة في السي (مثل البنية tm و الدالة clock)
  • استخدام الفئات CTime و CTimeSpan إذا كنا تستعمل Visula C++/MFC
  • استخدام الفئات TDate و TDateTime إذا كنا تستعمل C++ Builder/VCL
  • استخدام المكتبة boost::date_time إذا كنا نريد الحفاظ على كود Portable

تم تعديل هذه المشاركة بواسطة أحمد الشنقيطي في 31 مايو 2012 في 00:16

2
#11

آسف على التأخر

بارك الله فيكم

نحن قوم أعزنا الله بالإسلام فإن ارتضينا العزة بغيره أذلنا الله

عمر بن الخطاب رضي الله عنه وأرضاه

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