2012-10-14 40 views
1

我正在编写一个程序来打印出所有从0到100的数字,我需要找到一个变量的数字位数(在这种情况下变量为counter)。linux nasm程序集查找变量中保存的数字位数

这里是我的代码:

SECTION .data 
len EQU 32 

SECTION .bss 
counter resd len 
digit1 resd len 
digit2 resd len 
digit3 resd len 

SECTION .text 
GLOBAL _start 
_start: 
nop 

Print: 
mov eax, 4 
mov ebx, 1 
mov ecx, counter 
mov edx, len 
int 80h 

Set: 
mov BYTE [counter], 1 

Divide: 
; HERE IS WHERE I NEED TO FIND THE LENGTH OF THE VARIABLE COUNTER 
; initial division 
mov ax, [counter] ; number we want to print 
mov ch, 10 ; we divide by ten to siphon digits 
div ch  ; divide our number by 10 

; al now has 11, ah has 1 
mov dh, ah    ; save the remainder in dh 
xor ah,ah 
mov ch, 10    ; refill ch with the divisor 
div ch     ; al now has 1, ah now has 1 

Move:      ; now to move our digits to a printable state 
mov [digit1], dh  ; first digit is in edx 
mov [digit2], ah 
mov [digit3], al 

Adjust: 
add BYTE [digit1], '0' 
add BYTE [digit2], '0' 
add BYTE [digit3], '0' 

Print: 
mov eax, 4 
mov ebx, 1 
mov ecx, digit1 
mov edx, len 
int 80h 

mov eax, 4 
mov ebx, 1 
mov ecx, digit2 
mov edx, len 
int 80h 

mov eax, 4 
mov ebx, 1 
mov ecx, digit3 
mov edx, len 
int 80h 

Exit: 
mov eax, 1 
mov ebx, 0 
int 80h 

我需要找到长度,使我知道多少次来划分,也多少位数字打印变量计数器。

我怎样才能找到它是多久?

在此先感谢

+0

如果只是0到100,为什么不上'X <10'和'X <100'测试?那么你不必计算整个事情... – nneonneo

回答

1

对于范围内0..100数字,我只是比较的边界,用伪汇编,如:

mov ax, [counter] 

    mov cx, 3    ; default length 
    cmp ax, 100   ; >= 100, use 3 
    bge done 

    dec cx    ; set length to 2 
    cmp val, 10   ; >= 10, use 2 
    bge done 

    dec cx    ; set length to 1 

done: 
          ; cx now holds the digit count. 

实际上将处理高达999,但你可以如果您想扩大范围,还可以在100之前添加更多条件检查。

+0

谢谢!这很好。 – Progrmr

0

典型地,这与内部缓冲器完成(实际上栈会做:)

您划分Y = X模10(或Y = X MOD基),X = X格的基础上,直到X = 0(和推送每个模Y) 计数分割数,然后从堆栈C中弹出每个结果的次数 并写入输出流。

void print_number(int eax, int ebx) { // ebx = base, eax = number 
    int ecx = 0; 
    do { 
     edx = eax % ebx; 
     eax = eax/ebx; 
     push(edx); 
     ecx++; 
    } while (eax); 

    while (ecx) { 
     pop (eax); 
     putch(eax+'0'); 
     ecx--; 
    } 
} 

问题是,你最终会分割你需要的次数。

稍微更优化的事情是[再在C鼓励自己的思考] ...

void print_number(int a, int base) { 
    char string[10]; 
    static *ptr = string+9; // points to the last char of string 
    *ptr--=0;    // write ending ASCII Zero. 
    *ptr='0'; 
    while (a) { 
      *--ptr= '0'+(a % base); // works for base = 2-10 
      a/=base; 
    } 
    printf("%s",ptr); 
} 

你能找出为什么这个工程(或没有)?

+0

我不太明白你的意思。你能举个例子吗?确切地说,是 – Progrmr

1

亚基已经举了一个例子!使用“-S”开关编译它以查看编译器如何处理它 - 尽管这可能没有多大帮助。 :)

你问如何计算出数字的位数。我看过代码(来自一本着名书籍的作者!),它完成了一个完整的div循环,直到商数为零来计算数字。然后他做了另一个div循环找到他们!做> 10,> 100,> 1000等将工作。但你为什么需要知道?您可以保持div ing,直到商数为零,并计数数字。实际上,通过比较商数为9,您可以节省一个divdiv非常慢!) - 如果be,您的最后一位数字在al中。更简单的做额外div,国际海事组织。 :)

我们得到的“错误”顺序的余数/数字。我知道有三种方法可以解决这个问题。我认为“最简单”的方法就是将他们推入堆栈,对他们进行计数,然后按照我们要存储/打印的顺序弹出对话框,在之前或之后添加“0”。

另一种方法是从缓冲区的“后面”开始工作“前进”。这就是阿基的颂歌。对于C兼容的代码,返回零终止的字符串是好的,但sys_write不知道零终止的字符串,它想知道长度。 (没问题,我们可以找到一个“zstring”的长度)注意,这不会到达缓冲区的开始。如果你不关心“C兼容”代码,你可以返回“我们到达缓冲区的位置”和长度 - 可能在ecxedx这里sys_write想要它们。或者你可以在缓冲区的开始部分使用空格键。在列中右对齐的数字看起来不错。 :)

还有另一种方法是继续前进,并将em放在缓冲区中“倒退”,最后做一个“反向字符串”。

这些方法都不是非常快。 div很慢,期间!我“有”来自Terje Mathieson(一位“光速”解决方案专家)的代码,它不使用div,但我不明白它,也不使用它。如果你急着,可以在各种优化手册中找到它。 :)

通过将自己限制为100,你并没有获得太多收益。使用完整的32位寄存器编写例程也很容易(也许更容易),并且CPU对此感到满意。如果你需要处理负数,那只会更复杂一点。如果你在这里找不到例子,你可以在纳斯姆论坛找到一些例子,但是你自己尝试一下,这是一个有趣的练习。

呃......看......保留“太多”的内存可能会让你的程序“臃肿”,但不会造成任何伤害。保留“不够”的记忆是一个错误!所以你很好地在“太多”方面犯错。仍然...

SECTION .data 
len EQU 32 

SECTION .bss 
counter resd len 
digit1 resd len 
digit2 resd len 
digit3 resd len 

...使用128字节的缓冲区,以及打印32个字节的话,对于一个单一的数字/字符,好像很多。 :)

最佳, 弗兰克

+0

。如果你想知道数字的位数,你可以保留一个内部计数器,或者减去指针。无论如何,我认为人们不应该在乎多少分歧,因为它实际上并没有加快速度。 –