# Мама, я больше не боюсь целых чисел

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

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

Мама, я больше не боюсь целых чисел

Origin: http://samlib.ru/s/sapunow_p/mather.shtml

Создан: 29/05/2009, изменен: 29/05/2009, 22k

Миниатюра: Естествознание, Юмор

Series: Математические миниатюры

____________________________________________________________

Потом я начал "причёсывать" его до вида приличного...

Что получилось - судить Вам...

Мама,

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

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

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

╖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

( то есть, зет не меньше нуля и меньше единицы ) Я подумал и нарисовал обратную функцию: 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)) = sW(F(t)) = t Например, задана функция s= t2 или, по иному, t=s0.5Тогда прямая функция - F(t)=t2 а обратная к ней функция равна W(s)= s0.5 Получаем: F(W(s))=( s0.5 )2 = sW(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)) Интересна функция  y = x+0.5*sign(x) Её график выглядит так: Понятно, что график обратной функции рисуется так: Значит, обратная функция равна:  x = y - 0.5*sign(y)при |y| > 0.5 Я не могу сдержаться от восхищения:

- Блин! Это действительно очень красиво!

Впрочем, Вы тоже начнёте ругаться такими красивыми ругательствами, когда прочтёте статью "Многоугольник с одной стороной"

В одном я уверен точно: "зачёт" по целым числам я, наверное, сдал... Георгию.

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

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

____________________________________________________________

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

Origin: http://samlib.ru/s/sapunow_p/mather.shtml

Создан: 29/05/2009, изменен: 29/05/2009, 22k

Миниатюра: Естествознание, Юмор

Series: Математические миниатюры