Advertisement
Marrin

Euler 10

Aug 9th, 2013
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;----------------------------------------------------------
  2. ; Project Euler - Problem 10
  3. ;
  4. ; Find the sum of all the primes below two million.
  5. ;
  6. ; Requirements:
  7. ;
  8. ;   * at least a 386 with math coprocessor
  9. ;   * about 192 KiB free RAM
  10. ;
  11. ; Usage: euler10.com
  12. ;
  13. ; Prints the sum to standard output.
  14. ;
  15. ; Return codes (%errorlevel%):
  16. ;
  17. ;   * 0 Okay.
  18. ;   * 1 Not enough memory for the sieve data left.
  19. ;
  20.     cpu 386
  21.     org 100h
  22.     [map all]
  23.  
  24. ; TODO Move the stack down to save some space.
  25. PROGRAM_SEGMENT_SIZE   equ 1000h   ; in paragraphs.
  26.  
  27. ;----------------------------------------------------------
  28. segment .data
  29. ; The limit up to which all prime numbers will be added.
  30. ; It is a variable instead of a constant which means the
  31. ; program may be extended to let the user enter this value
  32. ; at runtime.
  33. limit:  dd 2000000
  34.  
  35. segment .bss
  36. ; Segment of the sieve data.  The data may span more than one
  37. ; 64 KiB segment.  In the case of the 2 million limit given in
  38. ; the Project Euler problem #10 it will take up about 128 KiB.
  39. sieve_segment: resw 1
  40.  
  41. ;----------------------------------------------------------
  42. start:
  43.  
  44. segment .data
  45. .banner_txt:
  46.     db "Project Euler #10",13,10,13,10
  47.     db "Sum all prime numbers below $"
  48. .banner_txt2:
  49.     db '.',13,10,13,10,'$'
  50.  
  51. segment .text
  52.     mov ah,9
  53.     mov dx,.banner_txt
  54.     int 21h
  55.     xor edx,edx
  56.     mov eax,[limit]
  57.     call print_u64
  58.     mov ah,9
  59.     mov dx,.banner_txt2
  60.     int 21h
  61.  
  62.     call memory_init
  63.     call sieve
  64.     call add_primes
  65.     call print_u64
  66.  
  67.     mov ax,4c00h
  68.     int 21h
  69.  
  70. ;----------------------------------------------------------
  71. ; Check if enough memory is available and calculate the
  72. ; base segment for the sieve data behind the program memory.
  73. ;
  74. ; In: limit The number up to which the prime numbers should
  75. ;           be added up.
  76. ; Out: sieve_segment The start segment of the sieve data.
  77. memory_init:
  78.  
  79. segment .data
  80. .mem_txt:
  81.     db "Not enough memory.",13,10,'$'
  82.  
  83. segment .text
  84.     mov eax,[limit]
  85.     ; limit / 128 (/2 = only odd numbers, /8 = 8 bits per byte, /16 = paragraphs)
  86.     shr eax,8
  87.     inc ax      ; ("round" up.)
  88.     jz .not_enough_memory_error
  89.     add ax,PROGRAM_SEGMENT_SIZE
  90.     jc .not_enough_memory_error
  91.     cmp [2],ax
  92.     jb .not_enough_memory_error
  93.    
  94.     ; Calculate and store the first segment address of the sieve data.
  95.     mov ax,cs
  96.     add ax,PROGRAM_SEGMENT_SIZE
  97.     mov [sieve_segment],ax
  98.  
  99.     ret
  100.  
  101. .not_enough_memory_error:
  102.     ; TODO Print amount of needed vs. available memory.
  103.     mov ah,9
  104.     mov dx,.mem_txt
  105.     int 21h
  106.     mov ax,4c01h
  107.     int 21h
  108.  
  109. ;----------------------------------------------------------
  110. ; Sieve of Eratosthenes implementation.
  111. ;
  112. ; In:   sieve_segment Start segment of the sieve data.
  113. ;       limit Up to this number the sieve determines prime numbers.
  114. ; Out:  [sieve_segment] Lookup bitarray with set bit for every odd prime number.
  115. sieve:
  116.  
  117. segment .bss
  118. .limit_sqrt:    resd 1
  119.  
  120. segment .text
  121.     call fill_sieve
  122.  
  123.     ; Zeroeth bit of sieve data = 0
  124.     mov bx,[sieve_segment]
  125.     mov es,bx
  126.     mov byte [es:0],11111110b
  127.  
  128.     ; Bounds for outer and inner loop.
  129.     fild dword [limit]
  130.     fsqrt
  131.     fistp dword [.limit_sqrt]
  132.     mov esi,[limit]
  133.     shr esi,1
  134.  
  135.     mov edi,3           ; i (EDI)
  136. .L1:
  137.     mov eax,edi
  138.     shr eax,1
  139.     call get_bit
  140.     jnc .not_prime
  141.  
  142.     mov edx,edi         ; j (EDX)
  143.     shr edx,1
  144.     add edx,edi
  145. .L2:
  146.     mov eax,edx
  147.     call get_bit        ; Called to initialise AX, CX, and ES:BX.
  148.     btr ax,cx
  149.     mov [es:bx],al
  150.  
  151.     add edx,edi
  152.     cmp edx,esi
  153.     jb .L2
  154.  
  155. .not_prime:
  156.     add edi,2
  157.     cmp edi,[.limit_sqrt]
  158.     jbe .L1
  159.  
  160.     ret
  161.  
  162. ;----------------------------------------------------------
  163. ; Fills the sieve data memory with set bits.
  164. ;
  165. ; As it fills with 32 bit values it may fill up to three
  166. ; excess bytes with set bits.
  167. ;
  168. ; In:   sieve_segment
  169. ;       limit
  170. ; Out:  [sieve_segmet] All set bits.
  171. fill_sieve:
  172.     mov bx,[sieve_segment]
  173.     mov es,bx
  174.  
  175. ; Fill whole 64 KiB segments.
  176.     mov eax,[limit]
  177.     shr eax,20
  178.     mov dx,ax
  179.     mov eax,0ffffffffh
  180. .L1:
  181.     or dx,dx
  182.     jz .whole_segments_finished
  183.     xor di,di
  184.     mov cx,4000h
  185.     rep stosd
  186.  
  187.     mov bx,es
  188.     add bx,1000h
  189.     mov es,bx
  190.  
  191.     dec dx
  192.     jmp .L1
  193.  
  194. .whole_segments_finished:
  195. ; Fill part of last 64 KiB segment.
  196.     mov ecx,[limit]
  197.     shr ecx,4
  198.     inc ecx
  199.     and ecx,0ffffh
  200.     xor di,di
  201.     rep stosd
  202.  
  203.     ret
  204.  
  205. ;----------------------------------------------------------
  206. ; Adds all the prime numbers below [limit].
  207. ;
  208. ; In:   [limit]
  209. ; Out:  EDX:EAX     64 bit integer with the sum.
  210. add_primes:
  211.  
  212.     xor edi,edi ; sum_hi (EDI)
  213.     mov esi,2   ; sum_lo (ESI)
  214.     mov edx,3   ; i (EDX)
  215. .L1:
  216.     mov eax,edx
  217.     shr eax,1
  218.     call get_bit
  219.     jnc .not_prime
  220.  
  221.     add esi,edx
  222.     jnc .skip
  223.     inc edi
  224. .skip:
  225.  
  226. .not_prime:
  227.     add edx,2
  228.     cmp edx,[limit]
  229.     jb .L1
  230.  
  231.     mov eax,esi
  232.     mov edx,edi
  233.     ret
  234.  
  235. ;----------------------------------------------------------
  236. ; Gets a bit from the bitarray (and a far pointer, and the byte value, and
  237. ; the bit offset within the byte value).
  238. ;
  239. ; in:   EAX bit offset.
  240. ;       sieve_segment
  241. ; out:  CF = bit value.
  242. ;       AL byte value.
  243. ;       ES:BX address of byte value.
  244. ;       CX bit offset within byte.
  245. get_bit:
  246.     mov cx,ax
  247.     and cx,00000111b
  248.     shr eax,3
  249.     mov ebx,eax
  250.     xor bx,bx
  251.     shr ebx,4
  252.     add bx,[sieve_segment]
  253.     mov es,bx
  254.     mov bx,ax
  255.     mov al,[es:bx]
  256.     bt ax,cx
  257.     ret
  258.  
  259. ;----------------------------------------------------------
  260. ; Prints an unsigned 64 bit integer value.
  261. ;
  262. ; In:   EDX:EAX Unsigned 64 bit integer value.
  263. print_u64:
  264.  
  265.     mov edi,eax
  266.     mov esi,edx
  267.     mov ebx,10
  268.     xor cx,cx           ; CX is digit counter.
  269. .L1:
  270.     mov eax,esi
  271.     xor edx,edx
  272.     div ebx
  273.     mov esi,eax
  274.  
  275.     mov eax,edi
  276.     div ebx
  277.     mov edi,eax
  278.     push dx
  279.     inc cl
  280.  
  281.     mov eax,edi
  282.     or eax,esi
  283.     jnz .L1
  284.  
  285. .print:
  286.     mov ah,2
  287.     pop dx
  288.     or dl,'0'
  289.     int 21h
  290.     loop .print
  291.  
  292.     ret
  293.  
  294. ;----------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement