Сапунов Павел
Мама, я больше не боюсь целых чисел

Самиздат: [Регистрация] [Найти] [Рейтинги] [Обсуждения] [Новинки] [Обзоры] [Помощь|Техвопросы]
Links
Кожевенное мастерство: сумки, ремни своими руками
 Ваша оценка:



  0x08 graphic
Потом я начал "причёсывать" его до вида приличного...
  0x08 graphic
Что получилось - судить Вам...

0x08 graphic

0x08 graphic
0x08 graphic
0x08 graphic
0x08 graphic

0x08 graphic

Мама,

я больше не боюсь

целых чисел...

(транкейт-математика)


 
  ї1 Георгий-искуситель
 
  В каждом отделе есть люди, которые любят работать, а есть другие, которым приходится...
  Жора не относился ни к тем, ни к другим. Своё предназначение он видел в том, чтобы "доставать" других. И этим приносил, как я считаю, огромную пользу обществу.
  Особенно ядовитым он был по понедельникам. Однажды, в один такой счастливый день он подошёл ко мне.
  - Я слышал, молодой человек,- Жора всех называл "молодыми", даже тех, кто старше его,- что Вы преуспеваете в деле программирования, особенно с использованием объектов из множества действительных чисел...
  - Да, я использую действительные числа. А как же иначе?
  - А может быть, Вам, молодой человек, лучше сначала целые числа досконально изучить?
  - Но целые я знаю...
  - Ой ли? Сколько будет два минус один?
  - Один,- улыбнулся я, ничего не подозревая.
  - А 3 минус 1?- Жора тоже улыбнулся, но ехидно.
  - Два...
  - А 4 минус 1?
  - Ну это слишком!- я возмутился.
  - Как говорят программисты - "истина остаётся истиной, даже если к ней прибавить ложь". Что в переводе на язык обречённых жить без программирования означает: "Истины много не бывает". Очень скоро ты это поймёшь. На тебе прогму одну. Набери её, а я потом подойду.
  Я взял "прогму". Вот что там было, в этой программе :
 
  uses crt ;
  var
  i :integer;
  x,z,a,b :real;
 
  begin clrscr;
 
  for i:=1 to 9 do
  begin
  a:=i+0.1;
  b:=1.1;
  z:= a - b;
  x:=trunc( z );
 
  writeln( 'trunc(',a:4:1,' - 1.1) = ',x:5:2);
  end;
 
  readln;end.
 
  А вот что выводила эта безобидная прогма на монитор:
 
  trunc( 1.1 - 1.1) = 0.00
  trunc( 2.1 - 1.1) = 0.00
  trunc( 3.1 - 1.1) = 1.00
  trunc( 4.1 - 1.1) = 3.00
  trunc( 5.1 - 1.1) = 4.00
  trunc( 6.1 - 1.1) = 5.00
  trunc( 7.1 - 1.1) = 6.00
  trunc( 8.1 - 1.1) = 7.00
  trunc( 9.1 - 1.1) = 8.00
 
  { Комментарий для тех, кто не знает языка программирования "Pascal": функция trunc(x) просто обрезает мантиссу действительного числа x. }
 
  Я поёжился, покряхтел, поохал, а через минуту ко мне подбежал не в меру счастливый Жорик:
  - Ну что, студент? Что скажешь?
  Я молчал. Наверно, я выглядел бледным, бедным и совсем больным. Дело в том, что в жизни я такого не встречал: я про "прогму".
  - Чего молчишь, как рыба, которая украла у рыбака кошелёк? Кстати, слово "кошелёк" теперь пишется через одно "ё" или через ё в квадрате? Надо отвечать так: в квадрате денег всегда больше... даже если их количество отрицательно... Это не я, это Стасик придумал! Как тебе?
  Мне сейчас было не до денег... Иногда бывает такое.
  - Я требую сатисфакции!- не унимался Жора,- скажи хоть что-нибудь, квазимодо души моей!
  Жора всегда "сыпал" смешными канделябрами непонятных выражений, когда у него было хорошее настроение. Я помолчал ещё с минуту, как того требовала дипломатия, и, наконец, сказал голосом поверженного оппонента:
  - Мама родная, я теперь боюсь целых чисел!
  Жора был счастлив как рыбак, которому какая-то совестливая рыба вернула слегка пожеванный "кошёлёк" с отрицательным червонцем в квадрате...
 
 
  ї2 В поисках...
 
  Честно говоря от чудачеств Жоры всегда была какая-либо польза. И в этот раз тоже: во-первых, я удивился, увидев то, что никогда раньше не видел. А это всегда заставляет думать. Во-вторых, я вообще зауважал транкейты - trunc(x). А когда кого-то или чего-то шибко уважаешь - от этого всегда огромнейшая польза. Потому что хуже всего, когда человек всех презирает и всех считает глупее себя - в этом случае человеку не у кого учиться и не к чему стремиться... Только не подумайте, что я понял это в ранней юности.
 
  Но обширно вспоминать юность я сейчас не собирался - лучше вспомнить, подумал я, всё, что я знаю о транкейтах ( о функциях trunc(x) ).
  Вспомнилась простая формула:
 
  round(x) = trunc(x+0.5)
  ( комментарий: функция round(х) округляет Х до ближайшего целого )
 
  Но при ближайщем рассмотрении оказалось, что она работает только при положительных Х. Испортив некоторое количество бумаги, я написал точную формулу:
 
  round(x) = trunc(x+0.5*sign(x))
 
  Она мне понравилась. Подумав, я написал ещё одну:
 
  round( -x) = trunc( -x -0.5*sign(x))
 
  поскольку я уже знал, что:
 
  trunc(-x) = -trunc(x) ( знак выносится )
  sign(-x) = -sign(x)
 
  ( По своему отношению к знакам обе эти функции похожи на синус. )
 
  А затем написал, почти не думая:
 
  trunc(a+b)=
  trunc(a)+trunc(b)+trunc(a+b-trunc(a)-trunc(b)) (1)
 
  И напрасно не думал, поскольку эта формула тоже жила только при положительных a и b.
  И тут я понял, почему я написал формулу (1) "не думая" - потому что в это время я на самом деле решал задачку Жоры. В его "прогму" надо просто добавить маленькое число "диди":
 
  uses crt ;
  const Dd=1E-10;
  var
  i :integer;
  x,z,a,b :real;
 
  begin clrscr;
 
  for i:=1 to 9 do
  begin
  a:=i+0.1;
  b:=1.1;
  z:= a - b;
  x:=trunc( z + Dd );
 
  writeln( 'trunc(',a:4:1,' - 1.1) = ',x:5:2);
  end;
 
  readln;end.
 
  Объяснение простое: компилятор, перед тем, как складывать, переводит числа в двоичную систему, и отсюда возникают ошибки - мизерные, но... Если бы решались дифференциальные ураврения, то программа такие крохотные ошибки и не заметила бы, но поскольку мы в программе используем функцию транкейт, то компилятор записав вместо числа 2.0 весьма похожее число 1.999999999, выдаёт ответ:
 
  Trunc(2.0) равен: trunc(1.999999999) = 1
 
  Теперь можно было думать о формуле (1). Случай, когда оба числа a и b отрицательны, не интересен, так как знак минус можно спокойно вынести за транкейт. Значит мне интересно знать транкейт разности. Подумав, написал формулу:
 
  trunc(b-a) = trunc(b-1) - trunc(a)
  +trunc(1+b -trunc(b) -a +trunc(a) ) (2)
 
  В формулу (2) тоже пришлось добавить "диди":
 
  trunc( b-a ) = trunc(b -1 +Dd) -trunc(a +Dd)
  +trunc( 1 +b-trunc(b) -a+trunc(a+Dd) +Dd )
 
  где Dd=1E-10
 
  Область определения параметров: b>0, b>|a|
  Если надо вычислить trunc(2.1-4.6) ,то это надо сделать так: trunc(2.1-4.6) = -trunc(4.6-2.1).
  Конечно, можно было сделать формулу на все случаи жизни. Но зачем? Она будет сложной... А ведь если сказать честно, то и для формулы (2) не так легко найти практического применения.
  Но тем не менее, после этой никому ненужной формулы я нашел я ещё одну - ещё более страшную и ещё более ненужную:
 
  Trunc(b*b) = trunc(b)*trunc(b)
  +trunc(2*trunc(b)*(b-trunc(b)) )
  +trunc(b*b-trunc(b)*trunc(b)-trunc(2*trunc(b)*(b-trunc(b))))
 
  Написал я этого крокодила... и сказал себе на полном сурьёзе:
  - Мама, я больше не боюсь целых чисел!
 
 
  ї3 О пользе
 
  Честно говоря, я такой же человек как и все: тоже люблю пользу, деньги и удовольствия. Удовольствия я уже немного получил, денег от этих формул не дождёшься, а пользу всегда можно создать самому.
  Из всех вышеприведённых формул самая полезная наверно одна:
 
  trunc(-x) = -trunc(x)
 
  И самая короткая. И я решил придумать ещё одну - такую же полезную, по возможности такую же короткую.
  Поначалу у меня получались крокодилы невероятных размеров, но со временем я научился оформлять свои мысли кратко...
  И наконец... Вот она:
 
  Trunc(K*y) = K*trunc(y) +trunc(K*(y-trunc(y))) (3)
 
  Чтобы увидеть пользу её надо записать так:
 
  Trunc(K*y)/K=trunc(y)+trunc(K*(y-trunc(y)))/K (4)
 
  Ну как - уже увидели? Это формула для округления числа до определенного знака после десятичной точки. Например, чтобы округлить 3.14159 до 0.01, надо сделать так, по логике левой части (4):
 
  Trunc(3.14159 * 100)*0.01 = 3.14
 
  По логике правой части (4) делаем так:
 
  Trunc(3.14159) + trunc(100*(3.14159 -trunc(3.14159))*0.01 = 3 + trunc(100*0.14159)*0.01 = 3.14
 
  Теперь, я думаю, и Вы получили нужную долю удовольствия. Но честно я скажу: я верю в то, что все в мире формулы полезные - просто не всё мы умеем правильно использовать...
 
 
  ї4 О духовном
 
  Но польза от математики далеко не всегда бывает чисто практической. Иногда она бывает теоретической, или даже моральной, можно сказать, духовной. Например, когда простая вещь заставит Вас поверить во что-то более большее.
  Давно у меня был такой случай. Я не верил, что функция sign(x) является математической. Действительно, что математического в строках:
 
  Function sign(x:real):real;
  Begin
  if x<0 then sign:=-1;
  if x=0 then sign:=0;
  if x>0 then sign:=1;
  End;
 
  Я мог поверить во что угодно - в то, что эта функция "химическая", "патрульно-дорожная", "приказательно-заставлятельная" - не верил только в то, что она математическая... До тех пор, пока сам не написал такие строки:
  function sign(z:real):integer;
  const r=1E-38;
  BEGIN
  sign:= round( z/(abs(z)+r) );
  END;
  Придумав, найдя, создав то, во что ранее сам не верил, я удивился, поверил и принял истину: мир гораздо сложнее того, что мы о нем можем вообразить... Да... Мир прекрасен, и главное - гениально продуман.
  Но поскольку ума с течением времени у каждого человека приблавляется не слишлом много, то история опять повторилась. Теперь в отношении функции trunc(x) . До сих пор я не верил, что она математическая. Сидит внутри компилятора некий "червячок" и откусывает мантиссы у действительных чисел - ну что тут математического? Или обрезать кусачками провод, пусть даже по которому течёт с помощью интернета великая теорема Ферма - ну что тут математического? И вот настал день...
  Помните формулу (3)? Я напомню:
 
  Trunc(K*y) = K*trunc(y) +trunc(K*(y-trunc(y))) (3)
 
  Я подумал: а что если доказать, что у функции y-trunc(y) имеется обратная функция? Тогда бы я поверил, что функция y-trunc(y) является математической. Не знал я тогда, что дух математики и на сей раз решил меня удивить.
  Вот график функции z=y-trunc(y) :
  0x08 graphic

  z
 
  1
 
 
  1 y
  Область определения функции Z : 0 =< z <1
  ( то есть, зет не меньше нуля и меньше единицы )
 
  Я подумал и нарисовал обратную функцию:
 
  0x08 graphic
y
 
 
 
 
 
 
 
 
 
 
 
  z
 
  И записал её:
  y = z + C (5)
 
  здесь z - аргумент, но его область определения та же: 0 =< z <1
  а С - это переменная константа, она принимает целые положительные значения:
 
  С = 0, 1, 2, 3, ...
  Полученную обратную функцию (5) я подставил в формулу (3), и получил новую формулу:
 
  trunc(K*(z+C))= K*trunc(z+C)+trunc(K*z) (6)
 
  и не забывая, что:
  0=< z < 1
  C = 0, 1, 2, 3, ...
  K - тоже целое, положительное
 
  я подставлял различные допустимые значения в формулу (6). И пришел к выводу, что всё правильно.
  Функция y = z + C
  есть обратная для функции z = y - trunc(y)
 
  Несколько непривычно. Но всё верно. Есть такое свойство. Если F(t) - прямая функция, а W(s) - обратная к ней, то :
 
  F(W(s)) = s
  W(F(t)) = t
 
  Например, задана функция s= t2 или, по иному, t=s0.5
  Тогда прямая функция - F(t)=t2 а обратная к ней функция равна W(s)= s0.5
 
  Получаем:
 
  F(W(s))=( s0.5 )2 = s
  W(F(t))=( t2 )0.5 = t
 
  В нашем случае прямая функция: F(y) = y - trunc(y)
  А обратная: W(z) = z+C
  Поэтому пишем:
 
  F(W(z)) = z+C - trunc(z+C) = z+C-C = z
 
  Правда, непонятно, как записать зависимость обратной от прямой, то есть W(F(y))
  А всё потому, что мы получили удивительное сочетание: усечённая по области определения переменная z и переменная-константа С.
 
  В душе я понимаю как записать W(F(y)), но разум стесняется записать это на бумаге. Может быть, в следующий раз...
 
 
  ї5 И снова о пользе
 
  Разгоровы о духовном как правило кончаются, когда начинает работать конвейер прагматизма. Вспомните формулу:
  round(x) = trunc(x+0.5*sign(x))
 
  Интересна функция
 
  0x08 graphic
y = x+0.5*sign(x)
 
  Её график выглядит так:
 
 
 
 
 
 
 
 
  Понятно, что график обратной функции рисуется так:
  0x08 graphic

 
 
 
 
 
 
 
 
 
  Значит, обратная функция равна:
 
  x = y - 0.5*sign(y)
  при |y| > 0.5
 
  Я не могу сдержаться от восхищения:
  - Блин! Это действительно очень красиво!
  Впрочем, Вы тоже начнёте ругаться такими красивыми ругательствами, когда прочтёте статью "Многоугольник с одной стороной"
  В одном я уверен точно: "зачёт" по целым числам я, наверное, сдал... Георгию.
 

Павел Сапунов

27 августа 2008 года


 
 Ваша оценка:

Связаться с программистом сайта.

Новые книги авторов СИ, вышедшие из печати:
О.Болдырева "Крадуш. Чужие души" М.Николаев "Вторжение на Землю"

Как попасть в этoт список

Кожевенное мастерство | Сайт "Художники" | Доска об'явлений "Книги"