سؤال

أنا أكتب بعض التحولات الإحداثي (وبشكل أكثر تحديداً تحويل Joukoswky ، ويكيبيديا جوكوفسكي تحويل) ، وأنا مهتم بالأداء ، ولكن بالطبع الدقة. أحاول القيام بتحولات الإحداثيات بطريقتين:

1) حساب الأجزاء الحقيقية والمعقدة في منفصلة ، باستخدام دقة مزدوجة ، على النحو التالي:

double r2 = chi.x*chi.x + chi.y*chi.y;

//double sq = pow(r2,-0.5*n) + pow(r2,0.5*n); //slow!!!
double sq = sqrt(r2); //way faster!
double co = cos(atan2(chi.y,chi.x));
double si = sin(atan2(chi.y,chi.x));

Z.x = 0.5*(co*sq + co/sq);
Z.y = 0.5*si*sq;

حيث chi و z هي هياكل بسيطة مع double x و y كأعضاء.

2) استخدام المجمع:

Z = 0.5 * (chi + (1.0 / chi));

حيث Z و Chi معقدة. هناك جزء مثير للاهتمام هو أن الحالة 1) أسرع (حوالي 20 ٪) ، لكن الدقة سيئة ، مما يعطي خطأ في الرقم العشري الثالث بعد الفاصلة بعد التحويل العكسي ، بينما يعيد المجمع الرقم الدقيق. إذن ، المشكلة على COS (ATAN2) ، الخطيئة (ATAN2)؟ ولكن إذا كان الأمر كذلك ، كيف يتعامل المعقد مع ذلك؟

تحرير: فقط اكتشف أن هذا لم يكن بالضبط السؤال الذي كنت في ذهني. لا بد لي من القيام بالتحول العام

z = 1/2*(chi^n + (1/chi)^n) ، وحتى الآن كان الكود أعلاه هو الطريقة التي أحسب بها للقيام بذلك. أكثر دقة،

    double sq = pow(sqrt(r2),n); //way faster!
double co = cos(n*atan2(chi.y,chi.x));
double si = sin(n*atan2(chi.y,chi.x));

Z.x = 0.5*(co*sq + co/sq);
Z.y = 0.5*(si*sq - sq/si);

أيضا تصحيح الخطأ على ZY

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

المحلول

أعتقد أنه في 1) يجب أن يكون

Z.y = 0.5*(si*sq - si/sq);

إذا كنت تريد أداء جيد حقًا ، فقد ترغب في العودة إلى المبادئ الأولى ومراقبة ذلك

1/(a+ib) = (a-ib)/(a*a+b*b)

لا sqrt(), atan2() أو cos() أو sin().

نصائح أخرى

منح r = sqrt(x*x+y*y):

cos(atan2(y,x)) == x/r
sin(atan2(y,x)) == y/r

يجب أن يكون حسابه بهذه الطريقة أكثر دقة وأسرع.

عندما تقوم بتوصيل هذه القيم في الصيغ لـ ZX و ZY ، سيتم إلغاء الجذر التربيعي أيضًا ، لذلك ستترك مع عمليات حسابية أساسية فقط.

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