Потом я начал "причёсывать" его до вида приличного...
Что получилось - судить Вам...
Мама,
я больше не боюсь
целых чисел...
(транкейт-математика)
ї1 Георгий-искуситель
В каждом отделе есть люди, которые любят работать, а есть другие, которым приходится...
Жора не относился ни к тем, ни к другим. Своё предназначение он видел в том, чтобы "доставать" других. И этим приносил, как я считаю, огромную пользу обществу.
Особенно ядовитым он был по понедельникам. Однажды, в один такой счастливый день он подошёл ко мне.
- Я слышал, молодой человек,- Жора всех называл "молодыми", даже тех, кто старше его,- что Вы преуспеваете в деле программирования, особенно с использованием объектов из множества действительных чисел...
- Да, я использую действительные числа. А как же иначе?
- А может быть, Вам, молодой человек, лучше сначала целые числа досконально изучить?
- Но целые я знаю...
- Ой ли? Сколько будет два минус один?
- Один,- улыбнулся я, ничего не подозревая.
- А 3 минус 1?- Жора тоже улыбнулся, но ехидно.
- Два...
- А 4 минус 1?
- Ну это слишком!- я возмутился.
- Как говорят программисты - "истина остаётся истиной, даже если к ней прибавить ложь". Что в переводе на язык обречённых жить без программирования означает: "Истины много не бывает". Очень скоро ты это поймёшь. На тебе прогму одну. Набери её, а я потом подойду.
Я взял "прогму". Вот что там было, в этой программе :
usescrt ;
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)
( По своему отношению к знакам обе эти функции похожи на синус. )
И напрасно не думал, поскольку эта формула тоже жила только при положительных 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) не так легко найти практического применения.
Но тем не менее, после этой никому ненужной формулы я нашел я ещё одну - ещё более страшную и ещё более ненужную:
Написал я этого крокодила... и сказал себе на полном сурьёзе:
- Мама, я больше не боюсь целых чисел!
ї3 О пользе
Честно говоря, я такой же человек как и все: тоже люблю пользу, деньги и удовольствия. Удовольствия я уже немного получил, денег от этих формул не дождёшься, а пользу всегда можно создать самому.
Из всех вышеприведённых формул самая полезная наверно одна:
trunc(-x) = -trunc(x)
И самая короткая. И я решил придумать ещё одну - такую же полезную, по возможности такую же короткую.
Поначалу у меня получались крокодилы невероятных размеров, но со временем я научился оформлять свои мысли кратко...
Ну как - уже увидели? Это формула для округления числа до определенного знака после десятичной точки. Например, чтобы округлить 3.14159 до 0.01, надо сделать так, по логике левой части (4):
Теперь, я думаю, и Вы получили нужную долю удовольствия. Но честно я скажу: я верю в то, что все в мире формулы полезные - просто не всё мы умеем правильно использовать...
ї4 О духовном
Но польза от математики далеко не всегда бывает чисто практической. Иногда она бывает теоретической, или даже моральной, можно сказать, духовной. Например, когда простая вещь заставит Вас поверить во что-то более большее.
Давно у меня был такой случай. Я не верил, что функция sign(x) является математической. Действительно, что математического в строках:
Functionsign(x:real):real;
Begin
if x<0 then sign:=-1;
if x=0 then sign:=0;
if x>0 then sign:=1;
End;
Я мог поверить во что угодно - в то, что эта функция "химическая", "патрульно-дорожная", "приказательно-заставлятельная" - не верил только в то, что она математическая... До тех пор, пока сам не написал такие строки:
functionsign(z:real):integer;
const r=1E-38;
BEGIN
sign:= round( z/(abs(z)+r) );
END;
Придумав, найдя, создав то, во что ранее сам не верил, я удивился, поверил и принял истину: мир гораздо сложнее того, что мы о нем можем вообразить... Да... Мир прекрасен, и главное - гениально продуман.
Но поскольку ума с течением времени у каждого человека приблавляется не слишлом много, то история опять повторилась. Теперь в отношении функции trunc(x) . До сих пор я не верил, что она математическая. Сидит внутри компилятора некий "червячок" и откусывает мантиссы у действительных чисел - ну что тут математического? Или обрезать кусачками провод, пусть даже по которому течёт с помощью интернета великая теорема Ферма - ну что тут математического? И вот настал день...
Я подумал: а что если доказать, что у функции y-trunc(y) имеется обратная функция? Тогда бы я поверил, что функция y-trunc(y) является математической. Не знал я тогда, что дух математики и на сей раз решил меня удивить.
Вот график функции z=y-trunc(y) :
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)) = s
W(F(t)) = t
Например, задана функция s= t2 или, по иному, t=s0.5