محاسبه Ln X - اسمبلی

hamed182001

New Member
سلام
دوستان کسی برنامه ای داره که بشه ln x را تو اسمبلی حساب کرد.
من میخوام فرمول R=Ln X- Ln y را حساب کنه. (تا 2 رقم اعشار)
اگه کسی سورس برای محاسبه Ln داره برام بذاره ممنون میشم یا حداقل یکی راهنمایی کنه.
 

the_king

مدیرکل انجمن
سلام
دوستان کسی برنامه ای داره که بشه ln x را تو اسمبلی حساب کرد.
من میخوام فرمول R=Ln X- Ln y را حساب کنه. (تا 2 رقم اعشار)
اگه کسی سورس برای محاسبه Ln داره برام بذاره ممنون میشم یا حداقل یکی راهنمایی کنه.

اگه توضیحاتی که می نویسم براتون پیچیده است، شرمنده. تقصیر حقیر نیست، کار با کمک پردازنده ریاضی
و محاسبه و نمایش اعشاری نیاز به مهارت در کار با پشته (Stack) هم داره که رعایت ترتیب هایش کمی پیچیده است.

برای محاسبه Ln بایستی از Log2 (لگاریتم مبنای 2) کمک بگیریم، چون تنها مبنای لگاریتمی که کمک پردازنده های
خانواده 8087 محاسبه می کنند، مبنای 2 است. دستور FYL2X لگاریتم مبنای 2 یک عدد را محاسبه می کند.

شما کافیست که (Log2(x را بر (Log2(e تقسیم کنید تا (Ln(x بدست آید. برای محاسبه (Log2(e هم دستور
FLDL2E وجود دارد.

بایستی پیش از محاسبه توسط کمک پردازنده، آن عدد صحیح را توسط FILD به داخل پشته کمک پردازنده
انتقال دهیم و پس از محاسبه مقدار نهایی آنرا توسط دستور FISTP به درون یک عدد صحیح برگردانیم.
اما چون شما به دو رقم بعد از اعشار نیاز دارید، پیش از تبدیل به یک عدد صحیح، آنرا در 100 ضرب می کنیم.
عدد در واقع صحیح است، اما دو رقم یکان و دهگان اش را جزو اعشار در نظر می گیریم.

اگر X یک عدد صحیح دو بایتی (DW) و LNX100 هم یک حافظه دو بایتی دیگر برای ذخیره کردن Ln(x) * 100 باشد
(ضربدر 100 کردیم تا دو رقم بعد از اعشار را از دست ندهیم)، کد زیر آنرا محاسبه خواهد کرد :
کد:
        FLD1
        FILD    WORD PTR X
        FYL2X
        FLDL2E
        FDIV
        MOV     WORD PTR LNX100, 100
        FILD    WORD PTR LNX100
        FMUL
        FISTP   WORD PTR LNX100
        MOV     AX, WORD PTR LNX100

برای چاپ عدد موجود در LNX100 بایستی یک روتین اختصاصی داشته باشیم.
روتین print_ax یک عدد صحیح موجود در ax را روی صفحه نمایش نشان می دهد.
روتین print_ax100 با استفاده از روتین print_ax می تواند یک عدد صحیح را که در 100 ضرب شده، بصورت
اعشاری با دو رقم بعد از اعشار نمایش دهد.

کد زیر توسط یک کامپایلر ML مایکروسافت قابل کامپایل شدن است و به عنوان مثال Ln(123 را محاسبه و نمایش
می دهد (4.81) :
کد:
.MODEL  SMALL
.DATA
        X        DW 123
        LNX100   DW ?
.CODE
.STARTUP
        FLD1
        FILD    WORD PTR X
        FYL2X
        FLDL2E
        FDIV
        MOV     WORD PTR LNX100, 100
        FILD    WORD PTR LNX100
        FMUL
        FISTP   WORD PTR LNX100
        MOV     AX, WORD PTR LNX100
        CALL    print_ax100
        MOV     AH, 8
        INT     21h
.EXIT    0

print_ax100:
        MOV     BX, 100
        XOR     DX, DX
        DIV     BX
        PUSH    DX
        CALL    print_ax
        POP     AX
        OR      AX, AX
        JZ      print_finished
        PUSH    AX
        MOV     AH, 2
        MOV     DL, "."
        INT     21h
        POP     AX
        OR      AX, AX
        JGE     is_positive1
        NEG     AX
is_positive1:
        MOV     BL, 10
        DIV     BL
        ADD     AX, "00"
        PUSH    AX
        MOV     AH, 2
        MOV     DL, AL
        INT     21h
        POP     DX
        CMP     DH, "0"
        JE      print_finished
        MOV     DL, DH
        INT     21h
print_finished:
        RET
print_ax:
        OR      AX, AX
        JGE     is_positive2
        PUSH    AX
        MOV     AH, 2
        MOV     DL, "-"
        INT     21h
        POP     AX
        NEG     AX
is_positive2:
        MOV     CX, 0
        MOV     BX, 10
get_digits:
        MOV     DX, 0
        DIV     BX
        PUSH    DX
        INC     CX
        OR      AX, AX
        JNE     get_digits
        MOV     AH, 2
print_digits:
        POP     DX
        ADD     DL, "0"
        INT     21h
        LOOP    print_digits
        RET
.STACK
END

کد برنامه asm به همراه فایل اجرایی exe ضمیمه این پست می باشد.
 

پیوست ها

  • Assembly Ln.zip
    1.2 کیلوبایت · بازدیدها: 12

hamed182001

New Member
the_king عزیز خیلی ممنون از پست کاملتون.
من خودم درس اسمبلی را خیلی وقت پیش داشتم. این برنامه را هم تا حدود زیادی فهمیدم. ولی مشکل اینجاست که من دارم یه پروژه دانشجویی خیلی در سطح پایین مینویسم برای یکی از دوستام. و نمیتونم ار این سطح دستورات استفاده کنم. اگه بتونی یکم سطح پایین تر راهنماییم کنی خیلی ممنون میشم.
خودم دارم روی حلقه کار میکنم که با حلقه بنویسمش
 

the_king

مدیرکل انجمن
the_king عزیز خیلی ممنون از پست کاملتون.
من خودم درس اسمبلی را خیلی وقت پیش داشتم. این برنامه را هم تا حدود زیادی فهمیدم. ولی مشکل اینجاست که من دارم یه پروژه دانشجویی خیلی در سطح پایین مینویسم برای یکی از دوستام. و نمیتونم ار این سطح دستورات استفاده کنم. اگه بتونی یکم سطح پایین تر راهنماییم کنی خیلی ممنون میشم.
خودم دارم روی حلقه کار میکنم که با حلقه بنویسمش

برای یک برنامه در سطح مبتدی موضوع خیلی سختی انتخاب کرده اید، چون محاسبه Ln نیازمند محاسبات
اعشاریه که یا بایستی توسط کمک-پردازنده انجام شوند و یا خودتان روتین هایی برای ضرب و تقسیم و توان
اعشاری ایجاد کنید که خودش کار را پیچیده می کند. مخصوصا محاسبه e ^ x پیچیده است، چون x یک عدد
اعشاری است و با ضرب کردن پی در پی e در خودش قابل محاسبه نیست.

اگر می خواهید با حلقه پیاده سازی اش کنید بایستی از متد تقریبی نیوتون استفاده کنید، فرض کنیم که
x همان عددی باشد که می خواهیم (Ln(x را محاسبه کنیم :

1) ابتدا یک متغیر اعشاری a را برابر یک مقدار حدسی مثلا 1 قرار دهید.
2) مقدار اعشاری e (یعنی 2.71828182845905) را متغیر e قرار دهید.
3) مقدار نزدیک به صفر یک متغیر اعشاری epsilon را برای دقت محاسبه حلقه تعیین کنید، مثلا 0.0001
4) فرمول y = e ^ a را محاسبه کنید. بدیهی است که a اعشاری است و محاسبه کردن e به توان a خودش
یک روتین پیچیده است.
5) از اختلاف مقدار میان y و x قدر مطلق گرفته و در متغیری نظیر d قرار دهید. (|d = |x - y)
6) اگر مقدار d کمتر از epsilon بود، پس ما (Ln(x را با تقریبی در حد epsilon محاسبه کرده ایم و می توانیم به
مرحله آخر (مرحله 10) برویم.
7) مقدار جدید a را با فرمول (a = a - ((y - x) / y محاسبه می کنیم.
8) اگر مقدار a از عدد بزرگی مثل 200 بیشتر شد، آنرا به همان حد 200 تغییر می دهیم.
9) مجددا به مرحله 4 بر می گردیم و حلقه تکرار می شود.
10) مقدار a برابر (Ln(x بوده و با دقت epsilon محاسبه شده است.

پیاده سازی این الگوریتم خیلی پیچیده تر از استفاده از دستورات کمک-پردازنده است، مخصوصا که بعد از نوشتن
آن الگوریتم بایستی برای محاسبه e ^ a از سری های ریاضی کمک بگیرید :

epowx.gif


یک راه ساده تر هم این است که مقادیر e ^ 1 و e ^ 0.1 و e ^ 0.01 و ... رو قبلا در متغیر هایی ذخیره کرده و
از فرمول زیر برای ضرب کردن پی در پی این متغیر ها در هم استفاده کنید :

epowxy.gif


البته روتین های جمع و تفریق و ضرب و تقسیم اعشاری را به هر حال بایستی بسازید.
 
آخرین ویرایش توسط مدیر:

جدیدترین ارسال ها

بالا