Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 [ 40 ] 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

для вывода графика целочисленной функции, значения которой находятся в диапазоне от imin до imax, и хотите, чтобы крайними значениями по оси ординат были наименьшие кратные 10 числа, включающие imin и imax. Эти крайние значения равны (дай+ 10)* 10 и

((/max+ 9)+ 10)* 10, если воспользоваться "модульным" делением или делением с округлением к меньшему значению. Если же использовать обычное деление, вам придется писать код наподобие следующего:

if (imin >= 0) gmin = (imin/10) *10 ,-

else gmin = ((imin - 9)/10)*10;

if (imax >= 0) gmax = ((imax + 9)/l0)*10;

else gmax = (imax/10)*10;

Помимо того что "модульное" деление и деление с округлением к меньшему значению практичнее деления с отсечением, следует отметить, что неотрицательный остаток от деления требуется, пожалуй, чаще, чем остаток, который может принимать отрицательные значения.

Сделать выбор между "модульным" делением и делением с округлением к меньшему значению непросто, поскольку они отличаются только в случае отрицательного делителя, что встречается довольно редко. Обращение к существующим языкам программирования высокого уровня в этой ситуации не поможет, поскольку практически везде деление знаковых целых чисел х/у означает деление с отсечением. Некоторые языки программирования при делении целых чисел возвращают число с плавающей точкой, т.е. рациональное. Ничуть не проще ситуация с остатками от деления. В Fortran 90 функция MOD дает остаток от деления с отсечением, а функция MODULO - остаток от деления с округлением к меньшему значению (который может быть отрицательным). Аналогично в Common Lisp и ADA функция REM дает остаток от деления с отсечением, а MOD - остаток от деления с округлением к меньшему значению. В PL/I значение MOD неотрицательно (остаток от модульного деления). В Pascal операция А mod в определена только для в > о, а ее результат всегда неотрицателен (т.е. это остаток от модульного деления либо от деления с округлением к меньшему значению).

Как бы то ни было, мы не можем изменить мир, даже если бы и хотели это сделать, так что далее, следуя за большинством, будем использовать обычное (отсекающее) определение деления х+у.

Самое ценное свойство отсекающего деления заключается в том, что для dO выполняются следующие соотношения:

(-и)+ t/ = n + (-t/) = -(« + £/).

Однако к подобным преобразованиям в программах следует подходить осторожно, так как если п или d представляют собой наибольшее (по модулю) отрицательное число, то -и или ~d не могут быть представлены 32 битами. Операция (-2")+(-1) вызывает переполнение (результат не может быть представлен в виде знаковой величины в дополнительном коде), и на большинстве компьютеров результат окажется неопределенным либо операция - невыполненной.

Впрочем, некоторые пытаются. Язык IBM PL.8 использует модульное деление, а команда деления в машине Кнута MMIX использует деление с округлением к меньшему значению [48].



Знаковое целое (отсекающее) деление связано с обычным рациональным делением следующим соотношением:

n + t/:

V/d\

tattidQ,nd>0\ если d*0,nd<0.

Беззнаковое целое деление, т.е. деление, при котором и п и d рассматриваются как беззнаковые целые числа, удовлетворяет верхней части (1).

В дальнейшем рассмотрении темы используется ряд элементарных арифметических свойств, которые приводятся здесь без доказательства. Функции, возвращающие наибольшее целое число, меньшее данного (floor - "пол"), и наименьшее, большее данного (ceil - "потолок"), подробно описаны в [18, 38].

Теорема D1. Для действительного х и целого к справедливы следующие соотношения:

w=-r-i

x-l<[xJSx [xj<x<[xj + l хгк<\ х\>к х>к=>\ х\>к x<:k=[x\<,kz х<к + \ х<к<А\ х\<к

x<\x\<x + l

\х-\-\<х\х-]

х<к<\х\<к

х<к\х\<к

x>k=>\x\-S.kzx>k-l

х>к<А\х\>к

Теорема D2. Для целых п и d(d>0) справедливы соотношения:

n-d + \

n + d-\

npud<0 справедливы соотношения

n-d-V

n + d + \

Теорема D3. Для действительного х и целого d? справедливы соотношения [lx]/d\ = lx/d] и \lx-]/d]=lx/d].

Следствие. Для действительных чисел а иЬ (Ь) и целого dfiOсправедливы соотношения

Теорема D4. Для целых nud (d;) и действительного х справедливы соотношения

, если 0 < X <

- + х

- + х

, если-

9.1. ПРЕДВАРИТЕЛЬНЫЕ СВЕДЕНИЯ



в приведенной ниже теореме rem(«,<i) обозначает остаток от деления п на d. Для о

рицательных значений d действует следующее определение: rem(n,-t/) = rem(n,</), как

случае деления с отсечением и модульного деления. При л<0 функция K.m{n,d) не ис

пользуется (таким образом, при нашем использовании данной функции efe значения все гда неотрицательны).

Теорема D5. Для п>0 и d справедливы соотношения:

2Km{n,d) или ,„ , ,

2гет(«.)-И « rem(2n + U) =

Km{2n,d) =

(причем каждое из значений больше или равно О и меньше \d ).

2rem(n,t/) + l или 2Tzm{n,d)-\d\ + l

Теорема D6. Для п>0 и d справедливо соотношение:

rem(2n,2rf) = 2rem(n,t/).

Теоремы D5 и D6 легко доказываются исходя из базового определения остатка, т.е. что для некоторого целого q он удовлетворяет соотношению

n=qd + Km(n,d), О й rem(n,t/) < \d\,

где nSO и dO (п и d могуг быть не целыми, однако будем применять наши теоремы только к целым числам).

9.2. Деление больших чисел

Как и в случае умножения, деление больших чисел можно осуществить традиционным школьным способом "в столбик". Однако детали реализации такого метода на удивление сложны. В листинге 9.1 приведен алгоритм Кнута [39, раздел 4.3.1], реализован-

ный на языке С. В его основе лежит беззнаковое деление типа 32+16 =* 32 (на самом деле частное при такой операции деления имеет длину не более 17 бит).

Листинг 9.1. Беззнаковое деление больших целых чисел

int divmnu(unsigned short q[], unsigned short r[], const unsigned short u[], const unsigned short v[], int m, int n)

const unsigned b = 65536; Основание чисел (16 битов)

unsigned short *un, *vn; Нормализованный вид u и v

unsigned qhat; Предполагаемая цифра частного

unsigned rhat; Остаток

unsigned p; Произведение двух цифр

int s, i, j, t, k;

if (m < n I I n <= 0 I I v[n-l] == 0)

return i; Возвращается при некорректном параметре if (n == 1) Частный случай делителя из одной цифры

к = 0;

for (j = m - 1; j >= 0; j--)



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 [ 40 ] 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87