-1

I've been tasked with creating a program that will list composite numbers within a user identified range. To determine if a number is composite I will be dividing it and checking for a remainder of zero. My actual problem is trying to print the variable called "current" in my code. current is initialized to 3 and then incremented every loop, so I expect the number 4 to be printed first but 2 prints first. How is this possible, current never even gets to 2, it only increases from 3.

mov     ecx, terms
trial:
    inc     current
    mov     eax, current
    cdq
    mov     ebx, 2
    div     ebx
    cmp     edx, 0
    je      composite
    cmp     edx, 0
    jg      below


    composite:
        mov     edx, OFFSET current
        call    WriteDec
        call    CrLf

    below:
    loop    trial

If I input 9 I expect 4, 6 and 8 to print because these all leave a remainder of 0 when divided by 2. instead I get 2, 3, 4, 5 and 6 printed.

billy bob
  • 11
  • 5
  • 1
    off-topic: `cdq` is the right setup for `idiv`, not `div`. It *sign*-extends into EDX:EAX. You want to zero-extend with `xor edx,edx`. But really you want `shr eax,1` to do unsigned division by 2, not the very slow `div` instruction. (And `test al,1` first to check the remainder, or look at CF which holds the bit shifted out). – Peter Cordes Feb 17 '19 at 21:23
  • @PeterCordes I knew about cdq and idiv but for some reason when I comment out the cdq my program crashes. – billy bob Feb 17 '19 at 21:27
  • BTW, your algorithm is totally broken. You're only ever dividing by 2, so you can't detect composite numbers like `9 = 3*3`, only even numbers (which are trivial and don't need a loop). See [Checking if a number is prime in NASM Win64 Assembly](//codereview.stackexchange.com/q/204902) for a working trial-division loop. – Peter Cordes Feb 17 '19 at 21:29
  • It's not surprising your program crashed if you comment out `cdq` and don't replace it with `xor edx,edx`. If EDX>1 before `div` by 2, then the quotient of `EDX:EAX / EBX` won't fit in EAX, so the CPU raises a `#DE` exception. [When and why do we sign extend and use cdq with mul/div?](//stackoverflow.com/q/36464879) – Peter Cordes Feb 17 '19 at 21:31
  • @PeterCordes right now ive only implemented checking for even composite numbers, once I get that part working correctly I will account for the other composite numbers, do you know why current is not printing the way I expect it to? – billy bob Feb 17 '19 at 21:33
  • @PeterCordes that makes perfect sense about the sign extending – billy bob Feb 17 '19 at 21:34

1 Answers1

0

WriteDec takes its arg in EAX. It's printing that, not the pointer(!) that you put into EDX. WriteDec takes an integer by value

When you call WriteDec the first time (on the first even number after 3), EAX = 4/2 = 2, so that's what you print. Use a debugger to look at registers, you would have probably seen the 2 in EAX.


And BTW, your loop only checks for even numbers, not all composites. (And you're doing it in a massively inefficient way. Even is trivial, just test al,1 to test the low bit of EAX. This version is ready for us to expand to a trial-division loop after ruling out even numbers, but for now the simplest branching is just fall-through into print or not.

    mov     ecx, terms
    mov     ebx, current
trial:                  ; do {
    inc     ebx

    test     bl, 1
    jnz      odd           ; low bit set = not divisible by 2 = odd

    ;; TODO: trial division loop after ruling out even numbers
    ;; mov eax,ebx
    ;; xor edx,edx
    ;; div something  in a loop


    even:
        mov     eax, ebx    ; WriteDec takes an arg in EAX, and preserves all others
        call    WriteDec
        call    CrLf

    odd:
      cmp   ebx, ecx
      jb    trial       ; }while(current < terms)
      ;; The loop instruction is inefficient, don't bother with it
      ;; and you don't need a down-counter for the loop anyway
      ;; you already have terms

      mov    current, ebx    ; in case you care?

The simplest way to check for a composite is trial division: Checking if a number is prime in NASM Win64 Assembly.

If you want to print all composites up to a certain number, it would be much more efficient to run a Sieve of Eratosthenes to find odd composites up to a high enough value, then loop printing every even number, and odd numbers if their bitmap or bytemap entry is set in the sieve.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847