ZF

                              ГЛЮКОМОРЬЕ
                               by Sassa


...а как было обещано в прошлом нумере, вот решения к задачам.

Задачка про свап чисел.

Решений пришло множество, все хороши, и выделить особенно некого.

Все решения сводятся к такому:

    в одну  из  переменных  заносится  разница  двух  чисел ( то ли это
разность,  то ли это XOR-маска, то ли еще что (а что еще?) ). Следующим
шагом   вторая   переменная,   с  использованием  этой  маски  получает
модифицированное значение  --  значение  первой  переменной.  Теперь  с
помощью  все той же маски и второй переменной ( которая теперь содержит
значение первой ) получаем начальное значение второй переменной.

( хихик-с! во, наговорил! J
...
a=a+b;
b=a-b;
a=a-b;
...




Задачка про сортировку чисел.

    Решений на эту задачку пришло очень мало.  То есть,  одно.  ;(  Это
анонимная группа студентов из конференции RELCOM.COMP.LANGS.C-C++

    Задача сводится   к  сортировке  двух  чисел.  А  три  числа  можно
отсортировать так:

Swap( a, b );
Swap( a, c );
Swap( b, c );

    где функция Swap( x,  y ) возвращает в x - максимальное из x и y, а
в y - минимальное.

    Понятно, что   таким   образом   конечное  количество  чисел  можно
отсортировать, написав соотвествующую конечную программу. ;)

    Вышеупомянутой Группой студентов была предложена такая функция Swap
( x, y ):

void Swap( int &x, int &y ){
  int z=x+y;
  int c=abs(x-y);

  x=(z+c)/2;
  y=(z-c)/2;
};

    Очевидно, что  эта  программа  легко  модифицируется  для  работы с
действительными числами.

    Эта задача очень похожа на предыдущую,  с той  лишь  разницей,  что
стоит задача найти не просто разность чисел,  а найти разность большего
и меньшего  чисел,  и  никогда  не  наоборот.  Именно  эта  разность  и
вычисляется в c.

    Да, правда, еще загвоздка: теперь нужно к минимальному _прибавить_,
а из максимального _вычесть_ эту разность,  и  поместить  результаты  в
соответствующие  переменные.  Тут  трудно  сказать,  как до этого можно
додуматься, отметим только, что это выглядит так:

x=(z+c)/2=(x+y+c)/2 <=> x=((max+min)+(max-min))/2=2*max/2=max

y=(z-c)/2=(x+y+c)/2 <=> y=((max+min)-(max-min))/2=2*min/2=min



МОЛОДЦЫ!

( а что еще я могу сказать?.. ;)

    ...а если говорить об авторском  решении,  то  мне  оно  больше  не
нравится после решения студентов :-|.
    Оно не такое строго математическое, а скорее алгоритмическое:

однако, здесь используется дополнительная функция sgn...

function sgn( f:integer ):integer;
{
 SGN=1, f>=0
 SGN=0, f<0
}

begin
    sgn:=(f+1) div (abs( f )+1);  {нетрудно сделать trunc... и
оперировать с real}
end;

procedure Swap( var a, b:integer );
{
  a=max( a, b );
  b=min( a, b );
}

var f:integer;
begin
  f:=b-a;
  f:=f*sgn(f);

  a:=a+f;
  b:=b-f;
end;

    Здесь хитрость   в   функции   SGN:   возвращает   0,   если  число
отрицательное, 1 в противном случае:

Если f>0, то abs(f)=|f|=f => f/|f|==1.
    Если f<0,  то |f|>f => f/|f|<1 => [ |  (f/|f|)  |  ]=0  --
целая часть от модуля отношения.

    Однако, чтобы не было  деления  на  ноль,  добавим  к  числителю  и
знаменателю по 1. Для целых чисел операция [ | a/b | ] сводится к a div
b.

Теперь, после

f=b-a;
f=f*sgn(f);

    будет f==b-a,  если b-a>0 => b>a.  К a нужно прибавить (b-a). Что и
будет сделано.  f==0,  если b-a<0 => b<a.  Оставить все как есть. Что и
будет сделано.


--

Sassa

       _____
     @()(_)
     /\\


(C) NF, 1998-2004