Арифметика повышенной точности

Тема в разделе "WASM.BEGINNERS", создана пользователем tibibo, 20 апр 2008.

  1. tibibo

    tibibo New Member

    Публикаций:
    0
    Регистрация:
    19 апр 2008
    Сообщения:
    7
    Доброе время суток!
    Скажу срузу: я начал изучать язык ассемблера позавчера. Так что, не судите строго ))
    Вобщем есть задача: сложить два 80ти битных числа. Я понимаю, что на эту тему скорее всего уже написано много, однако мне щас нужно немножко доходчивых объяснений вместо многих мегабайт текста.
    Вобщем взял я для своей задачи пример из Зубкова и переделал его следующим образом:
    Код (Text):
    1. ;
    2.     .model  tiny
    3.     .code
    4.     .386       
    5.     org 100h    ; начало COM-файла
    6.  
    7. start: 
    8. ;выдача сообщения mess1
    9.     mov ah,9       
    10.     mov dx,offset mess1
    11.     int 21h    
    12.     mov dx,offset crlf
    13.     mov ah,9
    14.     int 21h    
    15.  
    16.     mov eax,dword ptr bigval_1[16]
    17.     add     eax,dword ptr bigval_2[16]      
    18.     mov     dword ptr bigval_3[16],eax 
    19.     mov     eax,dword ptr bigval_1[12]
    20.     adc     eax,dword ptr bigval_2[12]      
    21.     mov     dword ptr bigval_3[12],eax
    22.  
    23.     mov     eax,dword ptr bigval_1[8]
    24.     adc     eax,dword ptr bigval_2[8]      
    25.     mov     dword ptr bigval_3[8],eax
    26.     mov     eax,dword ptr bigval_1[4]
    27.     adc     eax,dword ptr bigval_2[4]      
    28.     mov     dword ptr bigval_3[4],eax
    29.  
    30.     mov     eax,dword ptr bigval_1
    31.     adc     eax,dword ptr bigval_2     
    32.     mov     dword ptr bigval_3,eax
    33. ;печать результата
    34.     call    print              
    35.     mov eax,dword ptr bigval_3[4]  
    36.     call    print
    37.  
    38.     mov eax,dword ptr bigval_3[8]  
    39.     call    print
    40.     mov eax,dword ptr bigval_3[12] 
    41.     call    print
    42.  
    43.     mov eax,dword ptr bigval_3[16] 
    44.     call    print
    45.     mov dx,offset crlf
    46.     mov ah,9
    47.     int 21h    
    48.     ret
    49. mess1   db  'REZULTAT = $'
    50. crlf    db  0Dh,0Ah,'$'
    51. bigval_1    dd   0FF00h,0FF00h,0FF00h,0FF00h,0FF00h
    52. bigval_2    dd   0FFh,0FFh,0FFh,0FFh,0FFh      
    53. bigval_3    dd   0h,0h,0h,0h,0h        
    54.  
    55. ; процедура побайтной выдачи содержимого регистра ЕАХ
    56. print:
    57.     mov esi,eax    
    58.     shr eax,24     
    59.     call    print_al   
    60.     mov eax,esi
    61.     shr eax,16     
    62.     call    print_al   
    63.     mov eax,esi
    64.     shr eax,8      
    65.     call    print_al   
    66.     mov eax,esi    
    67.     call    print_al   
    68. ret
    69. ; процедура print_al
    70. ; выводит на экран число в регистре AL в шестнадцатеричном формате
    71. print_al:
    72.     mov dh,al
    73.     and dh,0Fh     
    74.     shr al,4       
    75.     call    print_nibble   
    76.     mov al,dh      
    77.  
    78. ; процедура вывода 4 бит (шестнадцатеричной цифры)
    79. print_nibble:  
    80.     cmp al,10      
    81.     sbb al,69h     
    82.     das        
    83.  
    84.     mov dl,al      
    85.     mov ah,2       
    86.     int 21h    
    87.     ret        
    88.  
    89.     end start
    Результатом такой программы будет:
    Код (Text):
    1. REZULTAT =
    2. 0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF
    Однако,если я все правильно понимаю, то это число не 80-ти, а 160-ти битное:

    Код (Text):
    1. FFFFh = 1111 1111 1111 1111b
    Т.е. я ожидаю результат:
    Код (Text):
    1. FFFFFFFFFFFFFFFFFFFF
    Я написал вместо
    Код (Text):
    1. bigval_1    dd   0FF00h,0FF00h,0FF00h,0FF00h,0FF
    2. bigval_2    dd   0FFh,0FFh,0FFh,0FFh,0FFh  
    3. bigval_3    dd   0h,0h,0h,0h,0h
    вот так:
    Код (Text):
    1. bigval_1    dw   0FF00h,0FF00h,0FF00h,0FF00h,0FF
    2. bigval_2    dw   0FFh,0FFh,0FFh,0FFh,0FFh  
    3. bigval_3    dw   0h,0h,0h,0h,0h
    Но тогда в результате будет:
    Код (Text):
    1. 000100000100000100000100000100
    Вобщем мне кажется, что я не знаю каких-то основ, и понимаю все неправильно.
    Покажите плиз где затык и объясните,как нужно правильно.
    Только не нужно пожалуйста посылать в гугл. Мне нужна сейчас не информация, а простое и доходчивое объяснение что бы разобраться в самаом простом.
    Заранее благодарен.
     
  2. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    Хм... по-моему, 80 бит = 10 байт, а вы складываете ячейки из двадцатибайтного диапазона...
    Код (Text):
    1. mov eax, dword ptr bigval_1
    2. add eax, dword ptr bigval_2
    3. mov dword ptr bigval_3, eax
    4. mov eax, dword ptr bigval_1[4], eax
    5. adc eax, dword ptr bigval_2[4], eax
    6. mov dword ptr bigval_3[4], eax
    7. mov ax, word ptr bigval_1[8]
    8. adc ax, word ptr bigval_2[8]
    9. mov word ptr bigval_3[8], ax
    10. <...>
    11. bigval_1 dw 0FF00h, 0FF00h, 0FF00h, 0FF00h, 0FF00h
    12. bigval_2 dw 0FFh, 0FFh, 0FFh, 0FFh, 0FFh
    13. bigval_3 dw 5 dup (0)
     
  3. tibibo

    tibibo New Member

    Публикаций:
    0
    Регистрация:
    19 апр 2008
    Сообщения:
    7
    Спасибо за ответ.
    Попробовал. Получился такой код:
    Код (Text):
    1.     .model  tiny
    2.     .code
    3.     .386       
    4.     org 100h    ; начало COM-файла
    5.  
    6. start: 
    7. ;выдача сообщения mess1
    8.     mov ah,9       
    9.     mov dx,offset mess1
    10.     int 21h    
    11.     mov dx,offset crlf
    12.     mov ah,9
    13.     int 21h    
    14.  
    15.     mov     eax,dword ptr bigval_1
    16.     add     eax,dword ptr bigval_2      
    17.     mov     dword ptr bigval_3[8],eax
    18.     mov     eax,dword ptr bigval_1[4]
    19.     adc     eax,dword ptr bigval_2[4]      
    20.     mov     dword ptr bigval_3[4],eax
    21.     mov     ax,word ptr bigval_1[8]
    22.     adc     ax,word ptr bigval_2[8]    
    23.     mov     word ptr bigval_3,eax[8]
    24. ;печать результата
    25.     call    print              
    26.     mov eax,dword ptr bigval_3[4]  
    27.     call    print
    28.     mov eax,dword ptr bigval_3[8]  
    29.     call    print
    30.     mov dx,offset crlf
    31.     mov ah,9
    32.     int 21h     ; перевод строки
    33.     ret
    34. mess1   db  'REZULTAT = $'
    35. crlf    db  0Dh,0Ah,'$'
    36. bigval_1    dw   0FF00h,0FF00h,0FF00h,0FF00h,0FF00h
    37. bigval_2    dw   0FFh,0FFh,0FFh,0FFh,0FFh      
    38. bigval_3    dw   5 dup (0)     
    39.  
    40. ; процедура побайтной выдачи содержимого регистра ЕАХ
    41. print:
    42.     mov esi,eax    
    43.     shr eax,24     
    44.     call    print_al   
    45.     mov eax,esi
    46.     shr eax,16     
    47.     call    print_al   
    48.     mov eax,esi
    49.     shr eax,8      
    50.     call    print_al   
    51.     mov eax,esi    
    52.     call    print_al   
    53. ret
    54. ; процедура print_al
    55. ; выводит на экран число в регистре AL в шестнадцатеричном формате
    56. print_al:
    57.     mov dh,al
    58.     and dh,0Fh      ; DH - младшие 4 бита
    59.     shr al,4        ; AL - старшие (shr - логический сдвиг вправо)
    60.     call    print_nibble    ; вывести старшую цифру
    61.     mov al,dh       ; теперь AL содержит младшие 4 бита
    62. ; процедура вывода 4 бит (шестнадцатеричной цифры)
    63. print_nibble:      
    64.     cmp al,10       ; три команды, переводящие цифру в AL
    65.     sbb al,69h      ; в соответствующий ASCII-код
    66.     das         ; (см. описание команды DAS)
    67.  
    68.     mov dl,al       ; код символа - в DL
    69.     mov ah,2        ; номер функции DOS в AH (вывод символа)
    70.     int 21h     ; вызов функции  
    71.     ret         ; возврат из процедуры
    72.  
    73.     end start
    В результате при компиляции получаю ошибку:

    Код (Text):
    1. error A4910: cannot open file: L:\masm\work\ML.err
    2. bigval.asm(26) : error A2032:
    И почему здесь
    Код (Text):
    1.     mov     eax,dword ptr bigval_1
    2.     add     eax,dword ptr bigval_2      
    3.     mov     dword ptr bigval_3[8],eax
    4.     mov     eax,dword ptr bigval_1[4]
    5.     adc     eax,dword ptr bigval_2[4]      
    6.     mov     dword ptr bigval_3[4],eax
    7.     mov     ax,word ptr bigval_1[8]
    8.     adc     ax,word ptr bigval_2[8]    
    9.     mov     word ptr bigval_3,eax[8]
    мы выполняем только три раза сложение, в то время как нужно (если я правильно понимаю) сложить 5 двойных слов

    Код (Text):
    1. bigval_1    dw   0FF00h,0FF00h,0FF00h,0FF00h,0FF00h
    2. bigval_2    dw   0FFh,0FFh,0FFh,0FFh,0FFh      
    3. bigval_3    dw   5 dup (0)
    Я знаком с ассемблером только 3й день! Объясните пожалуйста все доходчиво и подробно.
    Спасибо.
     
  4. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    80 бит = 10 байт = 5 слов, в то время, как 5 двойных слов = 10 слов = 20 байт = 160 бит.
    Так что число хранится в десяти байтах, т.е. 2,5 двойных словах. Вот и получается, что младшие 64 бита складываются по двойным словам, а довески 16битные - как слова.

    Код (Text):
    1.     mov     eax,dword ptr bigval_1    ;складываем младшие 32 бита
    2.     add     eax,dword ptr bigval_2      
    3.     mov     dword ptr bigval_3,eax ;; здесь не [8]
    4.     mov     eax,dword ptr bigval_1[4]  ; "средние" 32 бита
    5.     adc     eax,dword ptr bigval_2[4]      
    6.     mov     dword ptr bigval_3[4],eax
    7.     mov     ax,word ptr bigval_1[8]     ; оставшиеся 16 бит
    8.     adc     ax,word ptr bigval_2[8]    
    9.     mov     word ptr bigval_3[8],ax;;здесь 16битный mov
     
  5. tibibo

    tibibo New Member

    Публикаций:
    0
    Регистрация:
    19 апр 2008
    Сообщения:
    7
    Спасибо, JAPH, немножко разобрался. Теперь вроде бы все работает.
    Только теперь бы еще разобраться вот с чем:
    моя программа теперь выглядит вот так
    Код (Text):
    1.     .model  tiny
    2.     .code
    3.     .386       
    4.     org 100h    ; начало COM-файла
    5.  
    6. start: 
    7. ;выдача сообщения mess1
    8.     mov ah,9       
    9.     mov dx,offset mess1
    10.     int 21h    
    11.     mov dx,offset crlf
    12.     mov ah,9
    13.     int 21h    
    14. ;расчет
    15.     mov     eax,dword ptr bigval_1
    16.     add     eax,dword ptr bigval_2      
    17.     mov     dword ptr bigval_3,eax
    18.     mov     eax,dword ptr bigval_1[4]
    19.     adc     eax,dword ptr bigval_2[4]      
    20.     mov     dword ptr bigval_3[4],eax
    21.     mov     ax,word ptr bigval_1[8]
    22.     adc     ax,word ptr bigval_2[8]    
    23.     mov     word ptr bigval_3[8],ax
    24. ;печать результата
    25.     call    print              
    26.     mov eax,dword ptr bigval_3[4]  
    27.     call    print
    28.     mov ax,word ptr bigval_3[8]
    29.     call    print
    30.     mov dx,offset crlf
    31.     mov ah,9
    32.     int 21h     ; перевод строки
    33.     ret
    34. mess1   db  'REZULTAT = $'
    35. crlf    db  0Dh,0Ah,'$'
    36. bigval_1    dw   1Ah,1Ah,1Ah,1Ah,1Ah   
    37. bigval_2    dw   6h,6h,6h,6h,6h    
    38. bigval_3    dw   5 dup (0)     
    39.  
    40. ; процедура побайтной выдачи содержимого регистра ЕАХ
    41. print:
    42.     mov esi,eax    
    43.     shr eax,24     
    44.     call    print_al   
    45.     mov eax,esi
    46.     shr eax,16     
    47.     call    print_al   
    48.     mov eax,esi
    49.     shr eax,8      
    50.     call    print_al   
    51.     mov eax,esi    
    52.     call    print_al   
    53. ret
    54. ; процедура print_al
    55. ; выводит на экран число в регистре AL в шестнадцатеричном формате
    56. print_al:
    57.     mov dh,al
    58.     and dh,0Fh      ; DH - младшие 4 бита
    59.     shr al,4        ; AL - старшие (shr - логический сдвиг вправо)
    60.     call    print_nibble    ; вывести старшую цифру
    61.     mov al,dh       ; теперь AL содержит младшие 4 бита
    62. ; процедура вывода 4 бит (шестнадцатеричной цифры)
    63. print_nibble:      
    64.     cmp al,10       ; три команды, переводящие цифру в AL
    65.     sbb al,69h      ; в соответствующий ASCII-код
    66.     das         ; (см. описание команды DAS)
    67.  
    68.     mov dl,al       ; код символа - в DL
    69.     mov ah,2        ; номер функции DOS в AH (вывод символа)
    70.     int 21h     ; вызов функции  
    71.     ret         ; возврат из процедуры
    72.  
    73.     end start
    и в результате её выполнения я получаю такой результат
    Код (Text):
    1. 002000200020002000200020
    Т.е. последние 4 цифры (0020) как бы лишние (правильно?).
    Я думал,что нужно в этом месте поиграться
    Код (Text):
    1.     call    print              
    2.     mov eax,dword ptr bigval_3[4]  
    3.     call    print
    4.     mov ax,word ptr bigval_3[8]
    5.     call    print
    но как не пытался получается какая-то ерунда.
    Где и что я опять прошляпил?
    Еще раз спасибо.
     
  6. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    Для начала, вы выводите не в том порядке. Чем старше разряды, тем больше номер байта, в котором он хранится. Вывод надо начинать со старших разрядов, т.е. с bigval_3[8], затем bigval_3[4] и bigval_3[0].
    Но вот в bgival_3[8] надо вывести только слово (вы ведь так и пишете - mov ax, bigval_3[8]), а процедура print выводит двойное слово, вот и получается, что она показывает мусор из старших бит eax.
    Код (Text):
    1. mov  al, bigval_3[9]
    2. call print_al
    3. mov  al, bigval_3[8]
    4. call print_al
    5. mov  eax, bigval_3[4]
    6. call print
    7. mov  eax, bigval_3
    8. call print
     
  7. tibibo

    tibibo New Member

    Публикаций:
    0
    Регистрация:
    19 апр 2008
    Сообщения:
    7
    Большое спасибо! Почти во всем разобрался и программа работет правильно.
    Вот так у меня получилось в окончатеьном варианте:
    Код (Text):
    1.     mov ax,word ptr bigval_3[9]
    2.     call    print_al
    3.     mov ax,word ptr bigval_3[8]
    4.     call    print_al
    5.     mov eax,dword ptr bigval_3[4]  
    6.     call    print
    7.     mov eax,dword ptr bigval_3 
    8.     call    print
    Только ещё один маленький вопрос просто для понимания:
    в этих двух числах
    Код (Text):
    1. bigval_1    dw   1Ah,1Ah,1Ah,1Ah,0DFh  
    2. bigval_2    dw   6h,6h,6h,6h,20h
    старшинство разрядов слева направо или справа налево? Или это зависит от того,в каком порядке их
    обрабатывать? Иными словами, при сложении этих чисел мы ожидаем результат
    Код (Text):
    1. 00FF0020002000200020
    2. или
    3. 002000200020002000FF
    Еще раз большое спасибо.
     
  8. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    tibibo
    на x86 BigEndian - старший байт по старшему адресу
     
  9. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    По-моему, как раз-таки Little-Endian отвечает за старший байт по старшему адресу.
    Такая придирка - зачем записывать слово bigval_3[9], если реально используется только байт?
     
  10. valterg

    valterg Active Member

    Публикаций:
    0
    Регистрация:
    19 авг 2004
    Сообщения:
    2.105
    tibibo
    тогда логичнее, чтоб не путать того, кто потом разбирать исходник будет :
    Код (Text):
    1.     mov al,word ptr bigval_3[9]
    2.     call    print_al
    3.     mov al,word ptr bigval_3[8]
    4.     call    print_al
    А вот так оптимальнее, т.к. каждый вызов принт - дорогой
    Код (Text):
    1.     xor eax,eax
    2.     mov ax,word ptr bigval_3[8]
    3.     call    print
    Но будут лишние нули при выводе.
     
  11. tibibo

    tibibo New Member

    Публикаций:
    0
    Регистрация:
    19 апр 2008
    Сообщения:
    7
    wsd
    JAPH
    Поправьте меня,если я ошибаюсь, но по-моему JAPH прав: LittleEndian отвечает за старший байт по старшему адресу
    http://publib.boulder.ibm.com/infocenter/comphelp/v7v91/index.jsp?topic=/com.ibm.aix.pli.doc/lsh-bigendian.htm

    JAPH
    да,ошибка. Спасибо, что заметили. Я исправил на:
    Код (Text):
    1.         mov al,byte ptr bigval_3[9]
    2.     call    print_al
    3.     mov al,byte ptr bigval_3[8]
    4.     call    print_al
    valterg
    Спасибо за ответ, конечно вы правы. Но скорее всего вы имели в виду
    Код (Text):
    1. mov al,[b]BYTE[/b] ptr bigval_3
    2. вместо
    3. mov al,[b]WORD[/b] ptr bigval_3
    Иначе при компиляции получается ошибка
    Код (Text):
    1. bigval.asm(25): error A2070:
    2. bigval.asm(27): error A2070:
     
  12. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    tibibo
    по смысловой нагрузке слов BigEndian - больший заканчивающий очевидней.
    по мануалам, да, ты прав - наоборот LittleEndian