سؤال

أحاول تحسين ما يلي. رمز الصوت عاليا يفعل هذا:

إذا كان = 0.775 وأحتاج إلى الدقة 2 DP ثم => 0.78

في الأساس، إذا كان الرقم الأخير هو 5، فهذا يتجول أعلى الرقم التالي، وإلا فإنه لا.

كانت مشكلتي أن 0.45 لا يجتمع إلى 0.5 مع نقطة عشرية واحدة، حيث يتم حفظ القيمة بنسبة 0.44999999343 .... و SetPrecision حول 0.4.

لهذا السبب أجبر SetPrecision على أن تكون أعلى setprecision(p+10) ثم إذا انتهت حقا في 5، أضف المبلغ الصغير من أجل التقريب بشكل صحيح.

بمجرد الانتهاء، يقارن A مع سلسلة B ويعيد النتيجة. المشكلة هي أن هذه الوظيفة تسمى بضعة مليارات مرة، مما يجعل كراو البرنامج. أي أفكار أفضل حول كيفية إعادة كتابة / تحسين هذا وما هي الوظائف في التعليمات البرمجية ثقيلة جدا على الجهاز؟

bool match(double a,string b,int p) { //p = precision no greater than 7dp

    double t[] = {0.2, 0.02, 0.002, 0.0002, 0.00002, 0.000002, 0.0000002, 0.00000002};

    stringstream buff;
    string temp;

    buff << setprecision(p+10) << setiosflags(ios_base::fixed) << a; // 10 decimal precision
    buff >> temp;

    if(temp[temp.size()-10] == '5')  a += t[p]; // help to round upwards

    ostringstream test;
    test << setprecision(p) << setiosflags(ios_base::fixed) << a;
    temp = test.str();

    if(b.compare(temp) == 0) return true;

    return false;
}
هل كانت مفيدة؟

المحلول

كتبت الروتين الفرعي الجذر الصحي عدد صحيح مع أي شيء أكثر من زوجين عشر خطوط ASM، مع عدم وجود API يدعو على الإطلاق - ولا يزال بإمكانه القيام بحوالي 50 مليون متركروت / ثانية (كان هذا منذ حوالي خمس سنوات ...).

النقطة التي أقوم بها هي أنه إذا كنت تذهب إلى مليارات المكالمات، فستتخنق تكنولوجيا اليوم.

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

الشيء الوحيد المتبقي للقيام به بعد ذلك هو استبدال أكبر عدد أكبر من خطوط C ++ بما تستطيع مع ASM مخصص - ولكن عليك أن تكون كمالا حول هذا الموضوع. تأكد من أنك تستفيد بالكامل من كل دورة CPU والتسجيل - بالإضافة إلى كل بايت من ذاكرة التخزين المؤقت لوحدة المعالجة المركزية ومساحة المكدس.

قد تفكر في استخدام القيم العدد الصحيحة بدلا من النقاط العائمة، لأن هذه هي صديقة للأقأس وأكثر كفاءة بكثير. يجب أن تضاعف الرقم بحلول 10 ^ 7 (أو 10 ^ p، اعتمادا على كيفية قياقتك لتشكيل منطقك) لتحريك العشرية على طول الطريق إلى اليمين. ثم يمكنك تحويل النقطة العائمة بأمان إلى عدد صحيح أساسي.

سيكون عليك الاعتماد على أجهزة الكمبيوتر للقيام بالباقي.

<--Microsoft Specific-->
سأضيف أيضا معرفات C ++ (بما في ذلك الأشخاص الثابتة، حيث يتم الوصول إلى Donnie Deboer المذكور) مباشرة من كتل ASM المتداخلة في رمز C ++ الخاص بك. هذا يجعل مضمون ASM نسيم.
<--End Microsoft Specific-->

نصائح أخرى

اعتمادا على ما تريد الأرقام ل، قد ترغب في استخدام أرقام نقطة ثابتة بدلا من النقطة العائمة. بحث سريع يحول هذه.

أعتقد أنك تستطيع فقط إضافة 0.005 للحصول على الدقة إلى مئات، 0.0005 لآلاف، وما إلى ذلك. SPRINPRING النتيجة مع شيء مثل "٪ 1.2F" (مائة، 1.3F الألف، وما إلى ذلك) ومقارنة السلاسل. يجب أن تكون قادرا على طاولة ize أو معلمات هذا المنطق.

يمكنك حفظ بعض الدورات الرئيسية في التعليمات البرمجية المنشورة الخاصة بك من خلال جعل هذا مزدوج T [] ثابت، بحيث لا تخصصه مرارا وتكرارا.

جرب هذا بدلا من ذلك:

#include <cmath>

double setprecision(double x, int prec) {
    return 
        ceil( x * pow(10,(double)prec) - .4999999999999)
        / pow(10,(double)prec);
}

ربما تكون أسرع. ربما حاول الدخول إليها أيضا، ولكن قد تؤذي إذا لم يساعد ذلك.

مثال على كيفية عمله:

2.345* 100 (10 to the 2nd power) = 234.5
234.5 - .4999999999999 = 234.0000000000001
ceil( 234.0000000000001 ) = 235
235 / 100 (10 to the 2nd power) = 2.35

تم اختيار .49999999999999 بسبب دقة C ++ مزدوجة على نظام 32 بت. إذا كنت على منصة 64 بت، فربما تحتاج إلى المزيد من NINES. إذا قمت بزيادة NINES أكثر على نظام 32 بت فائض وتضغط بدلا من أعلى، فإن IE 234.00000000000001 يتم اقتطاعه إلى 234 في بيئة مزدوجة (بي 32 بت.

باستخدام النقطة العائمة (تمثيل غير دقيق) يعني أنك فقدت بعض المعلومات حول الرقم الحقيقي. لا يمكنك ببساطة "إصلاح" القيمة المخزنة في المزدوج عن طريق إضافة قيمة هرع. قد يحدد ذلك حالات معينة (مثل .45)، لكنه سيفطر حالات أخرى. سوف تنتهي في نهاية المطاف أعمس الأرقام التي كان يجب تقريبها.

إليك مقالة ذات صلة:http://www.theregister.co.uk/2006/08/12/Floating_Point_Proundoximation/

أنا آخذ في تخمين ما يعنيه حقا القيام به. أظن أنك تحاول معرفة ما إذا كانت السلسلة تحتوي على تمثيل عشري مزدوج بدقة. ربما يكون برنامج مسابقة حسابية وأنت تحاول معرفة ما إذا كان استجابة المستخدم "قريب بما فيه الكفاية" للإجابة الحقيقية. إذا كان الأمر كذلك، فقد يكون الأمر أكثر بساطة لتحويل السلسلة إلى مضاعفة ومعرفة ما إذا كانت القيمة المطلقة للفرق بين الزوجيين في حدود بعض التسامح.

double string_to_double(const std::string &s)
{
    std::stringstream buffer(s);
    double d = 0.0;
    buffer >> d;
    return d;
}

bool match(const std::string &guess, double answer, int precision)
{
    const static double thresh[] = { 0.5, 0.05, 0.005, 0.0005, /* etc. */ };
    const double g = string_to_double(guess);
    const double delta = g - answer;
    return -thresh[precision] < delta && delta <= thresh[precision];
}

احتمال آخر هو جولة الجواب أولا (في حين أنه لا يزال رقميا) قبل تحويله إلى سلسلة.

bool match2(const std::string &guess, double answer, int precision)
{
    const static double thresh[] = {0.5, 0.05, 0.005, 0.0005, /* etc. */ };
    const double rounded = answer + thresh[precision];
    std::stringstream buffer;
    buffer << std::setprecision(precision) << rounded;
    return guess == buffer.str();
}

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

بقدر ما أراك تفحص ما إذا كانت مدورة على نقاط P تساوي ب.

insted من تغيير A إلى String، قم بعمل طريقة أخرى وتغيير السلسلة إلى المزدوج (الضربات والضوابط فقط أو additoins فقط باستخدام طاولة صغيرة) - ثم قم بتحريك كل من الأرقام والتحقق مما إذا كانت السرعة السرية في النطاق الصحيح (إذا P == 1 => ABS (PA) <0.05)

تطور الزمن القديم خدعة من الأعمار الداكنة من الجنيهات والشلن والباون في البلد القديم.

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

لذلك في حالتك، يمكنك تخزين بياناتك في وحدات 200 من كل ما تعول فيه، قم بعمل حسابات صحيحة بسيطة على هذه القيم وتقسيمها بنسبة 200 في متغير تعويم كلما أردت عرض النتيجة.

أقوم بتعزيز أن لدي مكتبة "بيئة" هذه الأيام، لكن لمتطلباتك لسرعة وقت التشغيل قد تستبعد هذا الحل الممتاز.

يبدو وكأنه ما تحاول القيام به ليس تقريب حقيقي. 0.45 هو في الواقع 0.45 في الترميز الثنائي، و 0.44999999343 ليس هو نفس الشيء.

قد تكون بحاجة إلى إجراء تقريب متعددة - أولا أن نقول 3 أماكن عشرية، ثم إلى اثنين، ثم إلى واحد.

السؤال هو، ما الذي تحاول إنجازه؟ يجب أن يكون معيار المباراة الخاص بك

abs(a-b) < 10 ** -p

في حين أن؟

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