Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

RFpro.ru: Ассемблер? Это просто! Учимся программировать


РАССЫЛКИ ПОРТАЛА RFPRO.RU

Лучшие эксперты в разделе

Коцюрбенко Алексей aka Жерар
Статус: Мастер-Эксперт
Рейтинг: 361
∙ повысить рейтинг »
Evgen aka Chuma
Статус: 3-й класс
Рейтинг: 252
∙ повысить рейтинг »
nikitos82.01
Статус: 1-й класс
Рейтинг: 2
∙ повысить рейтинг »

∙ Assembler

Номер выпуска:1635
Дата выхода:23.11.2016, 18:45
Администратор рассылки:Лысков Игорь Витальевич (Старший модератор)
Подписчиков / экспертов:31 / 13
Вопросов / ответов:1 / 1

Консультация # 190021: Здравствуйте! Прошу помощи в следующем вопросе: Как можно проще и быстрее, пожалуйста, помогите... с комментариями , пожалуйста, не понятно... Тема Использование операторов сравнения (cmp), условных(Jxx), безусловных (JMP) переходов и циклов (LOOOP). Задание из двух частей. В первом задании необходимо подсчитать количество <...

Консультация # 190021:

Здравствуйте! Прошу помощи в следующем вопросе:
Как можно проще и быстрее, пожалуйста, помогите... с комментариями , пожалуйста, не понятно...
Тема
Использование операторов сравнения (cmp), условных(Jxx), безусловных (JMP) переходов и
циклов (LOOOP).


Задание из двух частей. В первом задании необходимо подсчитать количество
чисел, соответствующих определенному условию на некотором числовом промежутке.
Во втором задании требуется модифицировать свою программу так, чтобы найти и
вывести на экран двухсотое число или пару чисел соответствующих заданному
условию. Если таких чисел меньше двухсот, то вывести об этом сообщение на экран.
На промежутке от 1 до 100 000
Подсчитать количество таких чисел X, что (Х+Х-1)div500 - простое число
Ответ вывести на экран

Дата отправки: 13.11.2016, 18:34
Вопрос задал: EccoVIP (Посетитель)
Всего ответов: 1
Страница онлайн-консультации »


Консультирует Лысков Игорь Витальевич (Старший модератор):

Здравствуйте, EccoVIP!
Вот программа, решающая следующую задачу:
для всех чисел Х из интервала 1:100000 находим частное от деления (Х+Х-1)/500
и проверяем его на простоту. Если простое, то считаем найденные числа.
Простота проверяется делением данного числа на все числа от 3 до √Х.
Четные числа отбрасываются сразу проверкой младшего бита на 0
Одновременно ищется 200-е число Х, удовлетворяющее условию (Х+Х-1)/500 - простое
Вывод числа делается последовательным делением числа на 10, сохранением остатка в стеке
с последующим выводом символов-цифр в обратном порядке

Код (Assembler) :: выделить код
	.model	small	;модель памяти
	.386		;будем использовать 32-битные регистры и команды сопроцессора

MINNUM equ 1		;начинаем счет с 1
MAXNUM equ 100000	;до 100000
DIVNUM equ 500		;делим на 500

	.stack	200h

	.data
sNumbersCount	db	"Numbers count = $"
sNumber200	db	"Number #200 = $"
sCountLess200	db	"Numbers count < 200", 0dh, 0ah, '$'
temp		dd	?	;здесь будет верхняя граница проверки на простое
number200	dd	?	;200-е число, удовлетворяющее условию
	
	.code
start:
	mov	ax, @data	;настроим сегментный регистр данных на сегмент данных
	mov	ds, ax	

	call	CalcSimples	;считаем простые числа
	
				;выводим результат
	lea	dx, sNumbersCount ;поясняющая строка
	mov	eax, ebx	;количество чисел, удовлетворяющих условию
	call	PrintData	;выводим

	cmp	ebx, 200	;сравним количество найденных чисел с 200
	jb	print_less_200	;меньше - просто выводим сообщение
	
				;выводим 200-е число
	lea	dx, sNumber200	;поясняющая строка
	mov	eax, number200	;само число
	call	PrintData	;выводим
	jmp	wait_key	;наожидание нажатия на клавишу

print_less_200:			;чисел меньше 200
	lea	dx, sCountLess200
	mov	ah, 9
	int	21h
	
wait_key:
	mov	ah, 0		;ждем нажатие на клавишу
	int	16h
	
	mov	ax,4c00h	;завершаем программу
	int	21h

CalcSimples	proc		;поиск чисел
	mov	esi, DIVNUM	;делитель 500
	xor	ebx, ebx	;счетчик чисел
	mov	edi, MINNUM	;X, начинаем с MINNUM=1
	mov	ecx, MAXNUM	;счетчик цикла = MAXNUM=100000
simple_loop:			;цикл поиска
	lea	eax, [edi*2-1]	;eax = X+X-1
	xor	edx, edx	;подготавливаемся к делению
	idiv	esi		;edx:eax / esi
	cmp	eax, 2		;рассматриваем частное от деления, отсеем числа меньшие 4
	jb	simple_next	;полученные числа, меньшие 2, игнорируем
	je	simple_found	;= 2 считаем простыми
	cmp	eax, 3
	je	simple_found	;= 3 также считаем простыми
				;числа >= 4 анализируем на простоту
	push	edi		;сохраним текущее число edi=X (EDI используется в процедуре)
	call	simple		;проверяем на простоту, результат в флаге C, 1/0 - простое/непростое
	pop	edi

simple_add:	
	adc	ebx, 0		;добавляем флаг С к счетчику найденных чисел
	cmp	ebx, 200	;найдем 200-е число
	jne	simple_next
	mov	number200, edi	;сохраним значение 200-го числа X, удовлетворяющее условию
simple_next:
	inc	edi		;следующее число Х
	loop	simple_loop	;на продолжение цикла
	ret
simple_found:			;явное указание, что число простое
	stc			;С=1
	jmp	simple_add	;на суммирование
CalcSimples	endp
	
;анализ на простоту числа eax путем деления на все нечетные числа, 
;начиная с 3, и заканчивая корню квадратному из числа
simple	proc 
	test	eax, 1		;отсеем четные числа по младшему биту
	je	simple_no	;четные числа - непростые!

	mov	edi, eax	;сохраним число
				;найдем максимальное число, до которого будем делить
				;его найдем, как корень квадратный из нашего числа
	mov	temp, eax	;сохраним в памяти
	fild	temp		;загрузим в сопроцессор
	fsqrt			;посчитаем корень
	fistp	temp		;и извлечем обратно в память, с округлением до ближайшего целого
	
	mov	ebp, 3		;начальное значение делителя = 3
simple_cmp:			;цикла проверки на простоту
	cmp	ebp, temp	;проверим, прошли ли крайнее значение
	jbe	simple_continue	;нет - на продолжение проверки
	stc			;да - прошли все, значит число простое
	ret
simple_continue:		;анализируем на простоту делением и проверкой остатка на 0
	mov	eax, edi	;наше число
	xor	edx, edx	;подготавиваемся к делению
	idiv	ebp		;edx:eax / ebp
	test	edx, edx	;проверяем остаток на 0
	jne	simple_inc	;не ноль - на следующий делитель
simple_no:
	clc			;разделилось нацело - число непростое!
	ret
simple_inc:
	add	ebp, 2		;следующий делитель
	jmp	simple_cmp	;на проверку выхода из анализа
simple	endp

PrintData	proc		;вывод сообщения
	push	eax		;сохраним выводимое число
	mov	ah, 9		;выведем строку, адрес в dx
	int	21h
	
	pop	eax		;наше число
				;сформируем цифры числа в стеке
	xor	cx, cx		;счетчик цифр
	mov	esi, 10		;будем делить на 10
digits_loop:
	xor	edx, edx	;готовимся к делению
	div	esi		;EDX:EAX / ESI
	push	dx		;сохраним остаток (очередную цифру) в стеке

	inc	cx		;считаем
	test	eax, eax	;есть еще?
	jne	digits_loop	;на продолжение
				;выведем число
	mov	ah, 2		;функция вывода символа из dl
print_loop:
	pop	dx		;извлекаем очередную цифру из стека (в обратном порядке)
	or	dl, '0'		;делаем из числа символ
	int	21h		;выводим
	loop	print_loop	;по всем цифрам
	mov	dl, 0dh		;перейдем на новую строку
	int	21h
	mov	dl, 0ah
	int	21h
	ret
PrintData	endp
	
	end	start		;конец программы с точкой входа

Консультировал: Лысков Игорь Витальевич (Старший модератор)
Дата отправки: 17.11.2016, 13:17

5
нет комментария
-----
Дата оценки: 17.11.2016, 15:18

Рейтинг ответа:

НЕ одобряю +1 одобряю!


Оценить выпуск | Задать вопрос экспертам

главная страница  |  стать участником  |  получить консультацию
техническая поддержка

Дорогой читатель!
Команда портала RFPRO.RU благодарит Вас за то, что Вы пользуетесь нашими услугами. Вы только что прочли очередной выпуск рассылки. Мы старались. Пожалуйста, оцените его. Если совет помог Вам, если Вам понравился ответ, Вы можете поблагодарить автора - для этого в каждом ответе есть специальные ссылки. Вы можете оставить отзыв о работе портале. Нам очень важно знать Ваше мнение. Вы можете поближе познакомиться с жизнью портала, посетив наш форум, почитав журнал, который издают наши эксперты. Если у Вас есть желание помочь людям, поделиться своими знаниями, Вы можете зарегистрироваться экспертом. Заходите - у нас интересно!
МЫ РАБОТАЕМ ДЛЯ ВАС!


В избранное