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

مساعدة في إخراج المتوسط الحسابي لمصفوفة Signed

مغلقمُجاب
بدأه kakarot2055 في 15 ديسمبر 2013 · 10 رد · 1,852 مشاهدة · في لغة Assembly لأنظمة 16, 32, 64 بت
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم 

 

عندنا مشروع في الجامعة تسليمه غداً لمادة المايكروبروسيسر 8086 يقوم بإخراج القيمة العظمى والصغرى والمتوسط الحسابي لمصفوفة مخزنة في الذاكرة بداخل البرنامج "ملف الكود" قيمها موجبة وسالبة Signed  وطباعتها 

 

 

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

; multi-segment executable file template.

data segment
    ; add your data here!
     Array dB 000h,013h,012h,020h,015h,07dh,0FEh,0D7h,055H,0f3h,02Dh,080h,0ffh,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 
     MaxI DB "The Maximum Value in Integer = $"
     Min1 DB "The Minimum Value in Integer = $"
     ten db 10 
     AVG DB "The Average Value in Integer = $"
     
ends



stack segment
    dw   128  dup(0)
ends

code segment
start:
; set segment registers:
    mov ax, data
    mov ds, ax
    mov es, ax

    ; add your code here
            
       LEA SI,ARRAY ; offset array to si pointer 
       MOV CL,[si+1] ; size of array 
       MOV Ch,[si] ; size of array
       MOV bL,00 ; initial value of Minimum  
       XOR AX,AX ; fast way to make Register 0
       MOV bH,BYTE PTR[SI] ; initial  value of Maximum 
  L1:
       
          
       
      CMP bL,BYTE PTR[SI] ; compare Minimum to the value of array
      JL L2
      MOV bL,BYTE PTR[SI]  ; make bl Minimum with value of si 
      L2:CMP bH,BYTE PTR[SI]  ;compare Maximum to the value of array
      JG L3
      MOV bH,BYTE PTR[SI] ;make bl  Maximum with value of si 
  L3: 
         
    mov al,[si]
      cwd 
      
Test Al,Al
jS Nega
 add DI,ax
 adc dx,0
 Jmp Result
  nega:neg ax
  sub DI,ax
  sbb dx,0
   Result:
        INC si   
        loop L1 
            
            
              Call  Maximum ; call and Print  Maximum value of the array 
              TEST bl,BL ;test if bl positive or negative
               js  MinimumNN 
                               
               MinimumNN:  call MinimumN  ;  call and Print the  Minimum value and if the value negative go and print negative integer value  
                  JMP END
               
                      call Minimum
    END:    mov ah,4ch
                int 21h

            
 MinimumN PROC    NEAR    ;This Procedure To Convert The Hex Value to decimal values

 lea dx,Min1 ; Show The Massage 
 mov ah,9
 int 21h
 xor ax,ax
 xor dx,dx
 xor cx,cx
      mov al,bl         ; To Make The Result of Negative Value of Minimum correct 
         NEG AL   ;
mov cl,0ah
div cl
push ax
mov ah,00h
 div cl
push ax
mov ah,00h
 div cl
push ax
mov ax,0200h
  mov dl,"-"
  int 21h
pop dx
mov dl,dh
add dx,30h
int 21h
pop dx
mov dl,dh
add dx,30h
int 21h

pop dx
mov dl,dh
add dx,30h
int 21h

mov dl,10
int 21h


ret

  MinimumN  ENDP         
                    
   

Maximum PROC    NEAR 
     
   lea dx,MaxI
   mov ah,9           ; This Procedure To Convert The Hex Value to decimal values 
int 21h 
   xor ax,ax
   xor dx,dx
   xor cx,cx       
        mov al,bh
    mov cl,0ah
  div cl
push ax
and ah,00h
   div cl
push ax
and ah,00h
   div cl
push ax
  mov ax,0200h
 pop dx
mov dl,dh
add dx,30h
int 21h
 pop dx
mov dl,dh
add dx,30h
int 21h
 pop dx
mov dl,dh
add dx,30h
int 21h
 mov dl,10
int 21h
      
    mov dl,0dh 
    mov ah, 2
    int 21h   
    mov dl,0ah 
    mov ah, 2
    int 21h
ret
 Maximum ENDP

      
 


Minimum PROC    NEAR    ; If The Minimum Value is positive go here and print the result 

lea dx,Min1
mov ah,9
int 21h
xor ax,ax
   xor dx,dx
   xor cx,cx          
 mov al,bl
  mov cl,0ah
div cl
push ax
mov ah,00h
 div cl
push ax
mov ah,00h
 div cl
push ax
and ax,0200h
  mov dl,"-"
  int 21h
pop dx
mov dl,dh
add dx,30h
int 21h
pop dx
mov dl,dh
add dx,30h
int 21h

pop dx
mov dl,dh
add dx,30h
int 21h

mov dl,10
int 21h
       
    mov dl,0dh 
    mov ah, 2
    int 21h   
    mov dl,0ah 
    mov ah, 2
    int 21h

ret
  Minimum  ENDP           
     
  average1 PROC    NEAR
  
 xor ax,ax
   xor dx,dx
      
     mov aX,dI
    mov cl,0ah
  div cl
push ax
mov ah,00h
   div cl
push ax
mov ah,00h
   div cl
push ax
  mov ax,0200h
 pop dx
mov dl,dh
add dx,30h
int 21h
 pop dx
mov dl,dh
add dx,30h
int 21h
 pop dx
mov dl,dh
add dx,30h
int 21h
 mov dl,10
int 21h

ret   
   
   
   end start ; set entry point and stop the assembler.

طبعاً  average1 Proc  مازال لم يستخدم بعد قيمة المتوسط الحسابي عندي خاطئة 

 

 

الرجاء المساعدة 

#2

لتسهيل تتبع البرنامج الجزء الخاص بعملية إخراج المتوسط الحسابي  اسفل L3

#3 أفضل إجابة

الكود متداخل و غير مرتب و لا توجد ملاحظات كافية لفهم أجزائه و لم استطع تنقيحه و إليك بعض الملاحظات التى قد تساعدك فى حل المشكله:

 

1- المتوسط الحسابي هو مجموع العناصر و النتاج يقسم على عدد العناصر.

 

2- لا تستخدم ADC و استخدم ADD فأنت لا تحتاج للـ Carry فى شي و حدوث Overflow أمر طبيعي عند جمع رقم بإشارة مع أخر بدون إشاره و النتيجه ستكون صحيحه، فمثلا:

-13 + 25  = 12F3h + 19h = Ch = 12

3- بعد الإنتهاء من الجمع قم بإستخدام IDIV و لا تستخدم DIV حيث الأولى خاصة بقسمة الأعداد التى قد تحتوى على إشارة و الأخيره للأعداد الموجبة فقط.

 

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

 

 

و الله ولي التوفيق

تم تعديل هذه المشاركة بواسطة C++er في 15 ديسمبر 2013 في 19:45

مدونتي: C++ Tips and Tricks

#4

............

تم تعديل هذه المشاركة بواسطة kakarot2055 في 15 ديسمبر 2013 في 22:26

#5

سأفترض أن عنوان المصفوفة موجود داخل SI و حجمها كما قلت موجود داخل CX

   MOV AX, [SI] ; load value of first array element to ax
   XOR BX, BX   ; reset bx to use as counter
START:
   INC BX       ; increment bx
   CMP BX, CX   ; compare current index with total size
   JGE FINISH   ; go to finish if bx greater than or equals to cx
   ADD AX, [SI + 2*BX] ; get element at SI + 2*BX (the 2 are size of operand inside array)
   JMP START    ; loop
FINISH:
   XOR DX, DX   ; reset content of DX (explained below)
   CMP AX, 0    ; test
   JNS UNSIGNED_VAL
   MOV DX, -1   ; set dx to -1
UNSIGNED_VAL
   IDIV CX      ; divide [DX:AX] by CX, store the result back to AX

; division work on 32bit number, the hi part is in DX and low part in AX
; if AX have sign the we extend it to DX by setting it to -1, otherwise we set DX to 0

الكود من الذاكرة و لم اقم بتجربته و لكن المترض ان يعمل إذا وجدت مشكله ضعها هنا و ستجد الحل إن شاء الله.

 

 

و الله ولي التوفيق

تم تعديل هذه المشاركة بواسطة C++er في 15 ديسمبر 2013 في 21:10

مدونتي: C++ Tips and Tricks

#6

للأسف الناتج خاطىء 


 


طبعاً إستبدلت داخل   الكود  كل BX ب DI لأن ريجستر BX مشغولة بالقيم العظمى والصغرى 


 


ولا استطيع عمل LOOP أخرى بسبب أن البرنامج يجب ان يكون فعال ويحتاج زمن قليل 


تم تعديل هذه المشاركة بواسطة kakarot2055 في 15 ديسمبر 2013 في 22:25

#7

قمت بترجبة الكود و اتضح انى نسيت وضع colon بعد الكلمة UNSIGNED_VAL و غير ذلك وفالكود يعمل جيدا.

 

اقتباس
طبعاً إستبدلت داخل   الكود  كل BX ب DI لأن ريجستر BX مشغولة بالقيم العظمى والصغرى

إذا كان لديك stack يمكنك إستخدام PUSH و POP لحفظ قيم المسجلات و بعد ان تنتهي تقوم بإسترجاع القيمه منهم.

 

إليك النسخه 32بت التى قمت بتجربتها:

#include <cstdio>
using namespace std;

int main()
{
	int arr[] = {5, 0, 7, -9, 12, -120};
	int* addr = (int*)&arr;

   __asm
   {
      MOV ESI, addr
      MOV ECX, 6
   }

   __asm
   {
      MOV EAX, [ESI] ; load value of first array element to ax
      XOR EDI, EDI   ; reset bx to use as counter
   START:
      INC EDI       ; increment bx
      CMP EDI, ECX   ; compare current index with total size
      JGE FINISH   ; go to finish if bx greater than or equals to cx
      ADD EAX, [ESI + 4*EDI] ; get element at SI + 2*BX (the 2 are size of operand inside array)
      JMP START    ; loop
   FINISH:
      XOR EDX, EDX   ; reset content of DX (explained below)
      CMP EAX, 0    ; test
      JNS UNSIGNED_VAL
      MOV EDX, -1
   UNSIGNED_VAL:
      IDIV ECX
   }

   int res = 0;

   __asm
   {
	   MOV res, EAX
   }

   printf("%i", res);
}

كما ترى البرنامج سيطبع النتيجة بشكل صحيح، قم بتغيير محتويات المصفوفة و راقب عمل البرنامج.

استخدمت مترجم VC++2008SP1.

 

 

و الله ولي التوفيق

مدونتي: C++ Tips and Tricks

#8

هناك مشكلة في 

اقتباس

 

 

[SI + 4*DI]

 البرنامج يقول هناك مشكلة في هذا العنوان ؟؟ 

 

وإذا غيرتها ل si  وأصبحت 

[SI + [ 4 * SI]]

فأن هناك قيمة لل AVG ايضاً خاطئة 

 

هذا هو ملف البرنامج إن أحببت ان تلقي عليه نظرة 

 

AbdullaProject.asm

تم تعديل هذه المشاركة بواسطة kakarot2055 في 16 ديسمبر 2013 في 15:12

#9

بعد قراءة الكود علمت انه خطئى، المصفوفة لديك بمساحة واحد بايت للعنصر و ليس 2 بايت و بالتالي السطر:

[SI + 4*DI]

سيصبح

 [SI + DI]

حيث الرقم 4 أو 2 يمثل مساحة العنصر الواحد بالبايت داخل المصفوفة.

 

و الله ولي التوفيق

مدونتي: C++ Tips and Tricks

#10

كما قلت أخي الكريم هناك مشكلة في هذا السطر وهو أن برنامج emu8086 لا يقبل هذا الكود يقول هناك خطأ 

(58) [SI] cannot go with [DI] - wrong addressing!
#11
اقتباس
كما قلت أخي الكريم هناك مشكلة في هذا السطر وهو أن برنامج emu8086 لا يقبل هذا الكود يقول هناك خطأ

 

يمكنك إبدال السطر التالي:

      ADD AX, [SI + DI]

بهذا:

      INC SI      ADD AX, [SI]

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

      ADD SI, 2      ADD AX, [SI]

عموما خبرتي فى برمجة 16بت ضعيفة و كل محولاتي تكون بتحويل الكود من 32بت إلى 16بت مع إجراء التعديلات المناسبة.

 

 

بالنسبة لحل مشكلة المسجلات التى تحتوى على قيمة فانا لاحظت انك فمت بإنشاء stack داخل البرنامج فلماذا لا تقوم بدفع قيم هذه المسجلات داخله و اعادة إستخدامهم ثم ثقوم بإعادة محتواهم فى النهاية؟

 

 

و الله ولي التوفيق

تم تعديل هذه المشاركة بواسطة C++er في 17 ديسمبر 2013 في 18:10

مدونتي: C++ Tips and Tricks

هذا الموضوع مغلق.

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