نمایش نتایج 1 تا 40 از 42

نام تاپیک: دلفی و ریاضی

Hybrid View

پست قبلی پست قبلی   پست بعدی پست بعدی
  1. #1
    کاربر دائمی آواتار Ananas
    تاریخ عضویت
    آبان 1390
    محل زندگی
    طول 50 و عرض 34 درجه
    سن
    37
    پست
    894

    نقل قول: دلفی و ریاضی

    بسط تیلور توابع Ln و exp :

    function Ln_Taylor(X : Extended; Count : Integer = 5):Extended;
    const
    n_0_1 = 0.01;
    ln_1_01 = 0.00995033085316808284821535754426; // Ln(1.01)

    n_1_0_High = (1.0 + n_0_1);
    n_1_0_Low = (1.0 - n_0_1);

    arr : array[0..21] of Extended = (
    1.01, // 1.01 ^ (2 ^ 0 = 1)
    1.0201, // 1.01 ^ (2 ^ 1 = 2)
    1.04060401, // 1.01 ^ (2 ^ 2 = 4)
    1.0828567056280801, // 1.01 ^ (2 ^ 3 = 8)
    1.172578644923698520518625612016, // 1.01 ^ (2 ^ 4 = 16)
    1.3749406785310970541622913505711, // 1.01 ^ (2 ^ 5 = 32)
    1.8904618694795535717494712641154, // 1.01 ^ (2 ^ 6 = 64)
    3.5738460799561286443002337196205, // 1.01 ^ (2 ^ 7 = 128)
    12.77237580321778745481813393975, // 1.01 ^ (2 ^ 8 = 512)
    163.13358365862322124527961077082, // 1.01 ^ (2 ^ 9 = 1024)
    26612.566117305021291272917047288, // 1.01 ^ (2 ^ 10 = 2048)
    708228675.34793125625127947801295, // 1.01 ^ (2 ^ 11 = 4096)
    501587856585085410.3329144226122, // 1.01 ^ (2 ^ 12 = 8192)
    2.515903778736202094338585203235e+35, // 1.01 ^ (2 ^ 13 = 16384)
    6.3297718238591005455779113716959e+70, // 1.01 ^ (2 ^ 14 = 32768)
    4.0066011342120564182784035050917e+141, // 1.01 ^ (2 ^ 15 = 65536)
    1.6052852648669336927937427546953e+283, // 1.01 ^ (2 ^ 16 = 131072)
    2.5769407815989014605653704987392e+566, // 1.01 ^ (2 ^ 17 = 262144)
    6.6406237918675571564214160686182e+1132, // 1.01 ^ (2 ^ 18 = 524288)
    4.4097884345117453067721383354009e+2265, // 1.01 ^ (2 ^ 19 = 1048576)
    1.9446234037153549426176998268801e+4531, // 1.01 ^ (2 ^ 20 = 2097152)
    3.7815601822774923352439350246879e+9062 // 1.01 ^ (2 ^ 21 = 4194304)
    );
    var
    x_local, b, bb, b_n : Extended;
    scale_count : Int32;
    i, j : Integer;
    begin
    x_local := X;
    scale_count := 0;
    //------------------------------------------
    // Ln(A/B) = Ln(A) - Ln(B)
    // Ln(A) = Ln(A/B) + Ln(B)
    // .......... (if B == 1.01 then)
    //
    // Ln(A) = Ln(A / 1.01) + Ln(1.01)
    //
    // ..........
    // for i = 1 to count do
    // {
    // x /= 1.01
    // }
    // return Ln(x) + count * Ln(1.01)
    //
    //------------------------------------------
    j := 22;
    while ((x_local > n_1_0_High) and (j > 0)) do // x > 1.0
    begin
    Dec(j);
    while ((x_local > n_1_0_High) and (arr[j] < x_local)) do
    begin
    x_local := x_local / arr[j];
    scale_count := scale_count + Integer(1 shl j);
    end;
    end;
    j := 22;
    while ((x_local < n_1_0_Low) and (j > 0)) do // x < 1.0
    begin
    Dec(j);
    while ((x_local < n_1_0_Low) and ((1.0 / arr[j]) > x_local)) do
    begin
    x_local := x_local * arr[j];
    scale_count := scale_count - Integer(1 shl j);
    end;
    end;
    // ---------- Start Taylor block -----------------------------------------------
    //
    // b^3 b^5 b^6 b^7
    // Ln(a) = 2 ( b + ---- + ---- + ---- + ---- + ... )
    // 3 5 7 9
    // where :
    // a - 1
    // b = --------
    // a + 1
    //------------------------------------------------------------------------------
    b := (x_local - 1.0) / (x_local + 1.0);
    Result := b;

    b_n := b;
    bb := b * b;
    i := 3;
    while (i < (Count * 2)) do
    begin
    i := i + 2;
    b_n := b_n * bb;
    Result := Result + b_n / i;
    end;

    Result := Result * 2.0;
    // ---------- End Taylor block -------------------------------------------------
    Result := result + (ln_1_01 * scale_count);
    end;

    این بسط حول نقطه ی 1 سریع به جواب میرسه بخاطر همین تا جایی که میشه اعدادمون رو با روابط ریاضی میبریم نزدیک این مقدار بعد که Ln رو محاسبه کردیم دوباره با استفاده از روابط مذکور برمیگردونیم به مقدار مورد نظرمون.
    به همین خاطر اول یک عدد نسبتا نزدیک به یک مثلا 1.01 رو انتخاب کردم بعد یک آرایه از توان های اون ساختم به این شکل :
    اولین عضو آرایه = 1.01
    دومین عضو آرایه = عضو قبلی ضرب در خودش
    سومین عضو آرایه = عضو قبلی ضرب در خودش
    ...
    بعد عدد X رو تا جایی که میشه به این اعداد تقسیم کردم تا کلا به ضریبی از 1.01 تقسیم کرده باشیم (البته به مقدار کافی، نه زیاد نه کم). بعد Ln رو حساب میکنیم بعد از محاسبه به تعدادی که تقسیم بر 1.01 کردیم به همون تعداد با Ln(1.01) جمع میکنیم. جواب بدست میاد.
    برای اعداد کوچک تر از 1 هم تقسیم به ضرب تبدیل میشه و جمع به منها.
    ---------------------------------------------------
    exp :

    function Exp_Taylor(X:Extended; Count : Integer = 10):Extended;
    const
    arr_pow2 : array[0..12] of Extended = (
    2.00000000000000000000,
    4.00000000000000000000,
    16.0000000000000000000,
    256.000000000000000000,
    65536.0000000000000000,
    4294967296.00000000000,
    18446744073709551616.0,
    3.4028236692093846346337460743177e+38,
    1.1579208923731619542357098500869e+77,
    1.3407807929942597099574024998206e+154,
    1.797693134862315907729305190789e+308,
    3.231700607131100730071487668867e+616,
    1.0443888814131525066917527107166e+1233
    );
    e = 2.7182818284590452353602874713527;
    var
    i, j: Integer;
    x_n, x_local, e_pow : Extended;
    pow2_count : Int32;
    begin
    x_local := Abs(X);
    pow2_count := 0;
    j := 13;
    while ((x_local > 0.01) and (j > 0)) do
    begin
    Dec(j);
    while ((x_local > 0.01) and (0.001 < (x_local / arr_pow2[j]))) do
    begin
    x_local := x_local / arr_pow2[j];
    pow2_count := pow2_count + Integer(1 shl (j));
    end;
    end;

    (*
    x_local := Abs(X);
    j := Trunc(x_local);
    x_local := x_local - j;
    *)
    //---------------------------
    Result := 1.0;
    x_n := 1.0;
    for i := 1 to Count do
    begin
    x_n := x_n * (x_local / i);
    Result := Result + x_n;
    end;
    //---------------------------
    (*
    e_pow := 1.0;
    for i := 1 to j do
    e_pow := e_pow * e;
    Result := Result * e_pow;
    if X < 0 then
    Result := 1.0 / Result;
    *)

    for i := 1 to pow2_count do
    Result := Result * Result;
    if X < 0 then
    Result := 1.0 / Result;
    end;

    برای exp هم روشی مشابه داریم. به تعداد کافی عدد رو بر 2 تقسیم میکنیم تا کوچک بشه برسه نزدیک صفر. بعد exp رو حساب میکنیم بعد از محاسبه عدمون رو به همون تعداد که X رو بر 2 تقسیم کردیم، به توان 2 میرسونیم. یعنی اگر n بار به دو تقسیم کردیم، عدد به دست اومده از exp رو به توان 2 به توان n میرسونیم. یعنی یک حلقه ی n مرحله ای ه هر بار عدد رو در خودش ضرب میکنیم.
    روش دیگه ای که اون رو تو متن کد غیر فعال کردم هم روشی مشابه هست که میایم بخش اعشاری عدد رو نگه میداریم و بخش صحیح رو ازش یگیریم و exp رو برای بخش اعشاری بین 0 تا 1 حساب میکنیم بعد به تعدادی که در بخش صحیح ، 1 داریم (خود بخش صحیح) عددمون رو در e که exp عدد 1 هست ضرب میکنیم . این روش هم خوبه ولی روش تقسیمات متوالی اجازه میده که عددمون بیشتر به صفر نزدیک بشه. مثلا عدد 0.9 رو که نزدیک صفر هست میتونیم با تقسیمات متوالی بر 2 باز هم ک.چیکتر کنیم. پس من روش تقسیم به 2 رو ترجیح میدم.
    آخرین ویرایش به وسیله Ananas : دوشنبه 05 فروردین 1392 در 22:37 عصر

تاپیک های مشابه

  1. ساخت سیستم عامل با دلفی
    نوشته شده توسط amin_omega در بخش مباحث عمومی دلفی و پاسکال
    پاسخ: 20
    آخرین پست: سه شنبه 12 بهمن 1400, 11:38 صبح
  2. نوشتن علائم ریاضی دلفی
    نوشته شده توسط mohsenrahx در بخش مباحث عمومی دلفی و پاسکال
    پاسخ: 10
    آخرین پست: جمعه 19 مرداد 1386, 03:17 صبح
  3. کامپوننت نوشتن فرمولهای ریاضی در دلفی
    نوشته شده توسط Mohammadi_F در بخش کامپوننت های سایر شرکت ها، و توسعه کامپوننت
    پاسخ: 6
    آخرین پست: چهارشنبه 23 خرداد 1386, 07:21 صبح
  4. فارسی نوشتن در دلفی
    نوشته شده توسط (امید) در بخش مباحث عمومی دلفی و پاسکال
    پاسخ: 11
    آخرین پست: چهارشنبه 18 بهمن 1385, 07:56 صبح
  5. حل یکسری معادلات ریاضی ساده در دلفی
    نوشته شده توسط francosoft در بخش برنامه نویسی در Delphi
    پاسخ: 5
    آخرین پست: یک شنبه 23 اسفند 1383, 14:45 عصر

برچسب های این تاپیک

قوانین ایجاد تاپیک در تالار

  • شما نمی توانید تاپیک جدید ایجاد کنید
  • شما نمی توانید به تاپیک ها پاسخ دهید
  • شما نمی توانید ضمیمه ارسال کنید
  • شما نمی توانید پاسخ هایتان را ویرایش کنید
  •