06.09.2011, 21:40
общий
это ответ
Здравствуйте, Посетитель - 380267!
3) Предлагаю свою версию программы.
Работает со строками типа String.
В результате формируется строка String, состоящая из разных символов, и массив из Integer с количествами символов.
Массив из 256 integer необходимо передать параметром, он используется для подсчета, а также в нем возвращаются счетчики символов.
[code h=207]program q183962;
{$APPTYPE CONSOLE}
{$ASMMODE intel}
uses
SysUtils;
{процедура формирует String из разных символов и массив из количеств символов}
procedure CharsCount(Src:String; var Tgt:String; var Cnt:array of Integer); stdcall; Assembler;
asm
sub esp, 256 {выделим буфер под разные символы в стеке}
mov edx, esp {адрес буфера разных символов}
push edi {сохраним регистры}
push esi
push ebx
mov esi, Src {адрес исходной строки}
mov edi, Cnt {адрес счетчиков}
mov ecx, 256 {предполагаем, что там 256 dword-ов}
xor eax, eax {0}
rep stosd {обнуляем}
mov edi, Cnt {адрес счетчиков}
mov ecx, [esi-4] {длина исходного string-а}
jcxz @FormString {обойдем пустую строку}
@CalcCharsLoop: {цикл по символам строки}
lodsb {очередной символ}
inc dword ptr [edi+eax*4] {считаем в массиве счетчиков}
loop @CalcCharsLoop {по всем символам}
@FormString: {формируем результат}
xor ebx, ebx {индекс для 256 значений счетчиков}
xor eax, eax {счетчик разных значений}
mov ecx, 256 {счетчик в буфере}
@FormStringLoop: {цикл формирования результата}
mov esi, [edi+ebx*4] {читаем счетчик}
test esi, esi {проверяем на 0}
jz @FormStringNext {если 0, то обходим}
mov [edx+eax], bl {для ненулевого сохранякм индекс, как код символа}
mov [edi+eax*4], esi {и количество, сохраняем с начала массива счетчиков}
inc eax {считаем разные значения}
@FormStringNext: {на следующий счетчик}
inc ebx {индекс следующего счетчика}
loop @FormStringLoop {по всем}
{сформируем string из массива разных символов}
mov ecx, eax {количество}
mov eax, Tgt {адрес string}
{edx = адресу массива символов!}
call SetString {формируем string}
pop ebx {восстанавливаем регистры}
pop esi
pop edi
add esp, 256 {убираем из стека буфер}
end;
Var
i, N: integer;
a: string;
Tgt: string;
Cnt: array[0..255] of integer;
work: string;
num: string;
begin;
{вводим строку}
write('enter string:');
readln(a);
{выполняем задание}
CharsCount(a, Tgt, Cnt);
{сформируем результат}
N:=Length(Tgt); {длина строки}
{строка разных символов}
work:='Target = ' + Tgt + char(10)+'Counts = ';
for i:=0 to N-1 do {и счетчики}
begin
Str(Cnt[i],num);
work:=work+num+',';
end;
SetLength(work,Length(work)-1); {уберем последнюю запятую}
{выводим результат}
write(work);
readln;
end.
[/code]
4) Предлагаю свое решение и этой задачи тоже.
Расчет факториала ведется, начиная с 2 и с учетом предыдущего значения.
Чем достигается значительное убыстрение выполнения.
Каждый член произведения используется в виде (i! - 1) / i!
[code h=207]program q183962b;
{$APPTYPE CONSOLE}
{$ASMMODE intel}
uses
SysUtils;
{процедура вычисляет требуемое выражение}
{результат - в стеке сопроцессора}
function CalcValue(n: Integer):double; Assembler;
asm
sub esp, 4 {здесь будет число 2...n}
mov dword ptr [esp], 2 {начинаем с 2}
finit {инициализация сопроцессора}
fld1 {1, для накопления окончательного выражения}
fld st {1, для накопления факториала}
@mainLoop: {цикл расчета}
cmp [esp], eax {проверим, дошли ли до конца, EAX = n}
ja @finish {конец расчета}
fimul dword ptr [esp] {считаем факториал, умножая предыдущее значение на очередное}
fld st {посчитаем числитель, как i!-1}
fld1 {1}
fsubp st(1), st {числитель}
fdiv st, st(1) {получим (i!-1)/i!}
fmulp st(2), st {накапливаем произведения с потерей промежуточного частного}
inc dword ptr [esp] {на следующий член}
jmp @mainLoop {пока не дойдем до n}
@finish: {конец}
fstp st {уберем из стека сопроцессора n!, теперь st = посчитанной величине!}
add esp, 4 {уберем двойное слово из стека процессора}
end;
Var
n, pos: integer;
d: double;
a: string;
begin
{вводим число}
write('Enter number: ');
readln(a);
Val (a, n, pos); {преобразуем в число}
if pos<>0 then {проверка на корректность числа}
Writeln ('Error at position ',pos,' : ',a[pos])
else
begin
if (n>1) and (n<=1000) then {проверка на диапозон}
begin
{выполняем задание}
d := CalcValue(n); {считаем}
Writeln ('Value = ', d:10:8); {выводим}
end
else
Writeln ('Number must be from 2 to 1000');
end;
readln;
end.[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен