2016-12-14 79 views
1

我必須爲8086處理器準備程序,將四元數轉換爲八進制數。將四元數轉換爲八元數。 ASM 8086

我的想法:

乘以4的指數每個數字,並添加註冊。稍後檢查8的最高指數不高於第一步的總和。 除以8的指數直到餘數等於0.每個除法結果都是一個八進制數。 但是對於16位數的最後一位指數是4^15。我想這不是最佳算法。

有沒有其他辦法?也許可以二進制和3位數字組合。

+0

我不太清楚這裏的意圖。你打算輸入一個第四字符串作爲字符串,並需要打印爲八進制字符串?我認爲這是某種類型的學校項目(爲什麼還要用asm寫呢?),所以使用像itoa這樣的函數是不可能的? –

+0

是的,excactly用戶必須輸入第四個字符串,程序將打印八進制字符串。 –

+0

「16位數字」 - 16位8086可以保存在單個寄存器中的最大值是(十進制)65535(5位數)。這是(四元)33333333(8位數字)和(八進制)177777(6位數字)。如果你想支持16位數字,這將是一個有趣的項目。可能有一種簡單的方法可以直接從四位數字計算八進制數字,但我沒有看到它。每個(3bit)八進制數字將包含所有對應的(2bit)量化數字,以及其旁邊的數字的一部分。只需將整個量詞數加載到註冊表和解析中就簡單多了。 –

回答

1

原來你確實可以一次處理3個數字的值。以這種方式完成,您可以處理任意長度的字符串,而不受寄存器大小的限制。不知道爲什麼你可能需要,除非外星人嘗試使用長度很長的四位數字ascii字符串與我們溝通。可能發生。

可以以任何方式進行翻譯(從右到左或從左到右)。但是,對以下任何一個都有一些挑戰:

如果您正在處理RtL,則需要在開始之前知道輸出字符串的長度(以便在計算它們時知道在哪裏編寫數字)。這是可行的,但有點棘手。最簡單的說,長度是((strlen(Q)+ 2)/ 3)* 2。差不多得到它。但是,在許多情況下,您可以在開始處留出空白處。 「1」以及「10」將給出空白。 「20」不會。正確的值可以計算出來,但是很煩人。

同樣,處理LtR也有類似的問題。你沒有弄清楚在哪裏寫數字,但考慮:如果字符串將其轉換爲「123」,那麼轉換很簡單(33八進制)。但是如果你開始處理,並且完整的字符串是「1231」(155八進制)?在這種情況下,你需要像「0」(01 55)那樣處理它。 IOW,數字可以在3組進行處理,但你需要處理最初的情況下的位數不被3

發佈的解決方案平均分配到作業通常是什麼我儘量避免。然而,我懷疑你會把它作爲你的「解決方案」,而且(幾乎)不可能的是,谷歌可能會派人到需要類似東西的人那裏。

要注意的幾件事情:

  1. 這段代碼的目的是要在C稱爲使用微軟的快速調用(它使測試更容易),並與MASM編譯。
  2. 雖然它是用32位(我的環境)編寫的,但沒有什麼特別需要32位的。既然你說你的目標是8086,我試圖避免任何'高級'指示。轉換爲16位甚至64位應該不會帶來太大的挑戰。
  3. 它從左到右進行處理。
  4. 就像任何寫得很好的例程一樣,它會驗證其參數。它輸出一個長度爲零的字符串,例如輸入字符串中的數字無效。
  5. 如果輸出緩衝區爲NULL,它將會崩潰。我想我可以在錯誤返回一個布爾(目前返回void),但是,好了,我沒有。
  6. 我敢肯定,代碼可能是更嚴格的(不能總是?),但對於「功課工程質量,」這似乎是合理的。

除此之外,該評論應解釋代碼。

.386 
.model flat 
.code 

; Call from C via: 
; extern "C" void __fastcall PrintOct(const char *pQuat, char *pOct); 

; On Entry: 
; ecx: pQuat 
; edx: pOct 

; On Exit: 
; eax, ecx, edx clobbered 
; all others preserved 
; If pOct is zero bytes long, an error occurred (probably invalid digits) 

@[email protected] PROC 

; ----------------------- 
; If pOct is NULL, there's nothing we can do 
    test edx, edx 
    jz Failed 

; ----------------------- 
; Save the registers we modify (except for 
; eax, edx and ecx which we treat as scratch). 
    push esi 
    push ebx 
    push edi 

    mov esi, ecx 
    mov edi, edx 
    xor ebx, ebx 

; ----------------------- 
; esi: pQuat 
; edi: pOct 
; ebx: zero (because we use lea) 
; ecx: temp pointer to pQuat 

; Reject NULL pQuat 
    test esi, esi 
    jz WriteNull 

; ----------------------- 
; Reject 0 length pQuat 
    mov bl, BYTE PTR [esi] 
    test bl, bl 
    jz WriteNull 

; ----------------------- 
; How many chars in pQuat? 
    mov dl, bl ; bl is first digit as ascii. Preserve it. 

CountLoop: 
    inc ecx ; One more valid char 

; While we're counting, check for invalid digits 
    cmp dl, '0' 
    jl WriteNull 
    cmp dl, '3' 
    jg WriteNull 

    mov dl, BYTE PTR [ecx] ; Read the next char 
    test dl, dl ; End of string? 
    jnz CountLoop 

    sub ecx, esi 

; ----------------------- 
; At this point, there is at least 1 valid digit, and 
; ecx contains # digits 
; bl still contains first digit as ascii 

; Normally we process 3 digits at a time. But the number of 
; digits to process might not be an even multiple of 3. 

; This code finds the 'remainder' when dividing ecx by 3. 
; It might seem like you could just use 'div' (and you can), 
; but 'div' is so insanely expensive, that doing all these 
; lines is *still* cheaper than a single div. 
    mov eax, ecx 
    mov edx, 0AAAAAAABh 
    mul edx 
    shr edx, 1 
    lea edx, [edx+edx*2] 
    sub ecx, edx ; This gives us the remainder (0-2). 

; If the remainder is zero, use the normal 3 digit load 
    jz LoadTriplet 

; ----------------------- 
; Build a triplet from however many leading 'odd' digits 
; there are (1 or 2). Result is in al. 

    lea eax, DWORD PTR [ebx-48] ; This get us the first digit 

; If there was only 1 digit, don't try to load 2 
    cmp cl, 1 
    je OneDigit 

; Load the other digit 

    shl al, 2 
    mov bl, BYTE PTR [esi+1] 
    sub bl, 48 
    or al, bl 

OneDigit: 

    add esi, ecx ; Update our pQuat pointer 
    jmp ProcessDigits 

; ----------------------- 
; Build a triplet from the next 3 digits. 
; Result is in al. 

; bl contains the first digit as ascii 
LoadTriplet: 

    lea eax, DWORD PTR [ebx-48] 

    shl al, 4 ; Make room for the other 2 digits. 

    ; Second digit 
    mov cl, BYTE PTR [esi+1] 
    sub cl, '0' 
    shl cl, 2 
    or al, cl 

    ; Third digit 
    mov bl, BYTE PTR [esi+2] 
    sub bl, '0' 
    or al, bl 

    add esi, 3 ; Update our pQuat pointer 

; ----------------------- 
; At this point 
; al: Triplet 
; ch: DigitWritten (initially zeroed when computing remainder) 
ProcessDigits: 

    mov dl, al 
    shr al, 3 ; left digit 
    and dl, 7 ; right digit 

    ; If we haven't written any digits, and we are 
    ; about to write a zero, skip it. This deals 
    ; with both "000123" and "2" (due to OneDigit, 
    ; the 'left digit' might be zero). 

    ; If we haven't written any digits yet (ch == 0), and the 
    ; value we are are about to write is zero (al == 0), skip 
    ; the write. 
    or ch, al 
    jz Skip1 

    add al, '0' ; Convert to ascii 
    mov BYTE PTR [edi], al ; Write a digit 
    inc edi ; Update pointer to output buffer 

    jmp Skip1a ; No need to check again 

Skip1: 
    or ch, dl ; Both check and update DigitWritten 
    jz Skip2 

Skip1a: 

    add dl, '0' ; Convert to ascii 
    mov BYTE PTR [edi], dl ; Write a digit 
    inc edi ; Update pointer to output buffer 

Skip2: 

; Load the next digit. 
    mov bl, BYTE PTR [esi] 
    test bl, bl 
    jnz LoadTriplet 

; ----------------------- 
; All digits processed. We know there is at least 1 valid digit 
; (checked on entry), so if we never wrote anything, the value 
; must have been zero. Since we skipped it to avoid 
; unnecessary preceding zeros, deal with it now. 

    test ch, ch 
    jne WriteNull 
    mov BYTE PTR [edi], '0' 
    inc edi 

; ----------------------- 
; Write the trailing NULL. Note that if the returned string is 
; 0 bytes long, an error occurred (probably invalid digits). 
WriteNull: 
    mov BYTE PTR [edi], 0 

; ----------------------- 
; Cleanup 
    pop edi 
    pop ebx 
    pop esi 

Failed: 
    ret 

@[email protected] ENDP 

end 

我已經運行了一個具有1,000,000,000個四位數的字符串以及所有從0-4,294,967,295的值。似乎工作。

我是一個歡迎我們新的4位數字外星人領主。