Автор работы: Пользователь скрыл имя, 05 Декабря 2013 в 21:03, курсовая работа
Очень далеко от Греческого города Кротона, где творил Пифагор, а также много лет спустя, причём, вряд ли под непосредственным влиянием Пифагора, в России, были, оказывается творческие личности, которые не были связаны догматами о законченности арифметики. И, вот отличный пример того, как русские люди в очередной раз изобрели «пифагоровский» велосипед. К сожалению, точно неизвестно когда и кем конкретно было открыто сие, на мой взгляд, не менее великое изобретение.
ВВЕДЕНИЕ 5
1 АЛГОРИТМ УМНОЖЕНИЯ 7
2 ФЕНОМЕН РУССКОГО НАРОДНОГО УМНОЖЕНИЯ 8
3 АЛГОРИТМ RSA ШИФРОВАНИЯ 11
4 ПРЕДСТАВЛЕНИЕ ДЛИННЫХ ЧИСЕЛ 14
5 ОПЕРАЦИИ НАД ДЛИННЫМИ ЧИСЛАМИ 17
5.1 Сложение и вычитание 17
5.2 Умножение 19
5.3 Деление 20
6 ПРОБЛЕМЫ В ХОДЕ ВЫПОЛНЕНИЯ КУРСООЙ РАБОТЫ 22
ВЫВОДЫ 24
СПИСОК ЛИТЕРАТУРЫ 25
}
for (int i = 0; i < first_summand.Length; i++)
{
sum += (int.Parse(first_summand[i].
dop = (int.Parse(first_summand[i].
if (i == first_summand.Length - 1 && dop != 0)
{
sum += dop;
}
}
reverse(sum, ref sum);
}
Прежде всего, необходимо уточнить интерфейс. Можно определить операторы как части класса, и это будет достаточно удобно в использовании. Однако при вычислении C=A+B оператор не сможет получить доступ к числу C. Поэтому придется создавать временное число Temp = A+B, которое затем будет скопировано в C. Лишних операций и использования дополнительной памяти можно избежать, если записывать результат в C напрямую. Исходя их этого, в качестве интерфейса выберем внешние функции, которые принимают в качестве параметров исходные данные и число для записи результата.
Схема для сложения такова: складываем цифры слева направо (цифры хранятся в обратном порядке). Если зафиксировано переполнение (т.е. при сложении получена цифра, большая максимально возможной в данной системе счисления), то происходит “перенос” (carry) в следующий разряд
Вычисление C = A+B, работает вызов вида Add (A, B, C).Максимальный размер C должен быть достаточен для хранения суммы
static void Add(BigInt A,BigInt B, ref BigInt C)
{
ulong i;
int temp; // temp здесь и далее играет роль “временной” цифры,
// до выполнения переноса. Возможно, temp > BASE.
C.Coef = new int[A.Size+1];
short carry = 0;
// Добиваемся B.Size ≤ A.Size.
if (A.Size < B.Size)
{
Add(B, A, ref C);
return;
}
// Теперь B.Size ≤ A.Size.
// Складываем два числа, i - номер текущей цифры
for (i = 0; i < B.Size; i++)
{
temp=A.Coef[i]+B.Coef[i]+
if (temp >= Base) // переполнение. Перенести единицу.
{
C.Coef[i] = temp - Base; carry = 1;
}
else
{
C.Coef[i] = temp; carry = 0;
}
}
// Меньшее число кончилось
for (; i < A.Size; i++)
{
temp = A.Coef[i] + carry;
if (temp >= Base) // переполнение. Перенести единицу.
{
C.Coef[i] = temp - Base; carry = 1;
}
else
{
C.Coef[i] = temp; carry = 0;
}
}
// Если остался перенос
– добавить его в
if (carry == 1)
{
C.Coef[i] = carry; C.Size = A.Size + 1;
}
else C.Size = A.Size;
}
Вычитание осуществляется аналогично, с той лишь разницей, что осуществляется перенос “заимствования”. Мы работаем с положительными числами, поэтому если вычитаемое большое по размеру – происходит выход.
Если длины одинаковы, но одно больше другого – это приведет к тому, что в конце процесса останется неиспользованное заимствование, а результат будет дополнением до BaseB.Size. Например, при обычном вычитании 35 – 46 = -11, при описанном выше 35 – 46 = 89, так как выполняется равенство 89 = 100 – 11 (89 – это дополнение 11 до 100).
Рассмотрим случай, когда оба числа длинные. Обычно умножаются числа последовательно на одну цифру за другой, сохраняя временные результаты. Затем временные значения суммируются с учетом разряда. Однако можно ничего не хранить, а сразу прибавлять к окончательному результату.
1. Обнулить C.
3. Вычислить временный результат, соответствующий умножению i-й цифры A на число B, в процессе вычисления сразу прибавлять его к C, начиная с i-ой позиции. Если получившаяся цифра C больше Base – сделать перенос.
4. Если A не кончилось, увеличить i на единицу и идти на шаг 3.
Пусть делитель – обычное
число базового типа. В этом случае
деление выполняется очень
Рассмотрим действия, совершаемые при делении A=68971 на B=513 (рисунок 1.5.1). Здесь n=5, m=2.
Рисунок 1.5.1 Пример деления длинных чисел
(горизонтальные линии проводятся между шагами)
1. i = (индекс старшего коэффициента A) = 4
1.2 Вычитаем сдвинутое B*1 = 513 из A (на бумаге при этом пишем только значимую для следующего шага часть A)
4. i < m = 2, процесс закончен. То, что осталось от A после вычитаний, является остатком деления.
Все очевидно, за исключением
одного “творческого” шага – «угадывания».
Как заставить компьютер
Пусть очередной шаг представляет собой деление некоторого U = (u0, u1, …, un) на B=(b0, b1, …, bn-1). Если bn-1 ≥Base/2, то можно доказать следующие факты.
1. Если положить qGuess = (un*Base + un-1)/bn-1, то qGuess-2 ≤ q≤qGuess. Иначе говоря, вычисленная таким способом “догадка” будет не меньше искомого частного, но может быть больше на 1 или 2.
2. Если же дополнительно выполняется неравенство qGuess*bn-2 > Base*r + un-2, где r – остаток при нахождении qGuess и qGuess ≠ Base (условие 2), то qGuess-1 ≤ q ≤ qGuess, причем вероятность события qGuess = q+1 приблизительно равна 2/Base.
Таким образом, если bn-1 ≥ Base/2, то можно вычислить qGuess = (un*Base + un-1) / bn-1 и уменьшать на единицу до тех пор, пока не станут выполняться условия (2). Получившееся значение будет либо правильным частным q, либо, с вероятностью 2/Base, на единицу большим числом.
В ходе выполнения практической части моей курсовой работы возникло несколько проблем
Во-первых, мне хотелось улучшить быстродействие своей программы. А поскольку используются, в частности, очень большие числа, то этот фактор очень важен.
Изначально результаты деления и умножения чисел на 2 сразу записывались в listbox (в процессе подсчета) и после каждой следующей операции дописывались туда из-за чего умножение длинных чисел происходило значительно дольше из-за того, что вывод информации на экран занимает относительно много времени (речь идет о долях секунд и даже меньше, но при большем объеме вывода информации это очень заметно) !
После долгих экспериментов, я нашла, наконец решение проблемы. А именно: записывать результаты вычислений в строку (в тип string) - это позволяет не тратить лишнее время. А после всех вычислений надо было вывести эту строку.
Кодовая часть решения проблемы:
public void div_2_1(string a, ref int count, ref int[] chetn)
{
count = 0;
string b = "";
string[] str = { a };
string div2 = "";
int k = 0, q = 1, q1 = 0;
if (int.Parse(a[a.Length - 1].ToString()) % 2 == 1)
{
Array.Resize(ref chetn, chetn.Length + 1);
chetn[0] = 0;
q1++;
}
delenie_na_2.Text = str[0] + "\n";
while (a.ToString() != "1")
{
a = div_2(a, k, b);
Array.Resize(ref str, str.Length + 1);
a = delete_0(angel);
str[q] = a;
if (int.Parse(a[a.Length - 1].ToString()) % 2 == 1)
{
Array.Resize(ref chetn, chetn.Length + 1);
chetn[q1] = q;
q1++;
}
//delenie_na_2.Text += str[q] + "\n"; было
div2 += str[q] + "\n"; //стало
q++;
count++;
}
delenie_na_2.Text = div2; //стало
}
И так мы рассмотрели очень интересное и полезное изобретение человечества – русское народное умножение. Благодаря простоте алгоритма оно позволяет вычислять большие числа в машинном коде за минимальное время и при малом количестве занимаемой памяти. В процессе выполнения курсовой работы я открыла для себя этот алгоритм умножения, не только с практической стороны, но и узнала много нового для себя, например, о новых науках, о свойствах чисел, которые до сих пор неизвестны человечеству, не смотря на такое стремительное развитие технологий.
В математической логике русский народный счет тесно связан с алгоритмом шифрования RSA из-за способности работать с длинными числами.
Благодаря этому методу
человечеству открылась возможность
перемножать большие числа
В общем, это очень интересный и оригинальный способ, показывающий нам, что не все свойства чисел до конца исследованы человеком.
Этот метод умножение положил начало к вычислению больших чисел, а это, прошу заметить, не только очень важно для наук, но и интересно даже для людей далеких от математики.
1. Липский, В. Перестановки // Комбинаторика для программистов [Текст]. – М.: «Мир», 1988. – С. 214.
2. Морозова, О. И. Применение ЭВМ для решения задач математической логики и теории алгоритмов [Текст]: учеб. пособие / О. И. Морозова, Ю. К. Чернышев.; Нац. аэрокосм. ун-т «Харьк. авиац. ин-т», 2010.- С. 71.
3. Генерация перестановок
в лексикографическом порядке // «Генерация
перестановок в лексикографическом порядке» [Электронный
ресурс] / Режим доступа: \www/ URL: http://fit.nsu.ru/data_/
4. Томас Кормен, Чарльз Лэйзерстон, Рональд
Ривест «Алгоритмы построения и анализ»
// Алгоритмы и структуры данных, анализ
алгоритмов [Электронный ресурс] / Режим
доступа: \www/ URL: http://e-maxx.ru/bookz/files/