Новые возможности .NET 4.0: BigInteger

by Alexei 7. March 2010 16:31

BigInteger

В грядущей версии .NET Framework 4.0 наконец-то появится поддержка длинной арифметики. Новый тип BigInteger позволит работать с числами любого размера, ограниченного только объёмом имеющейся памяти. Помимо этого добавлен тип для работы с комплексными числами.

Новый класс  BigInteger находится в новом пространстве имен System.Numeric. ЧТобы его использовать нужно подключить библиотеку System.Numerics.dll(и лишний раз порадоваться скорости работы Add Reference в Visual Studio 2010)

 

 Новый объект класса BigInteger можно создать несколькими способами:

  • Используя оператор new. При этом в конструкторе можно передать любой интегральный тип или тип с плавающей точкой языка C#. При этом при использовании типов с плавающей точкой значащие цифры после десятичной точки будут отброшены:
BigInteger a = new BigInteger(123.99);
Console.WriteLine(a);
BigInteger b = new BigInteger(123456789);
Console.WriteLine(b);
  •  Объявив переменную типа BigInteger и присвоить ей значение любой другой переменной интегрального типа:
Int64 longValue = 6315489358112;
BigInteger bi = longValue;
Console.WriteLine(bi);
  • Чтобы присвоить объекту типа BigInteger переменную с плавающей точкой нужно воспользоваться операцией приведения типов:
double doubleValue = 4354548.9233;
BigInteger a = (BigInteger)doubleValue;
Console.WriteLine(a);
decimal decimalValue=345454.343m;
BigInteger b = (BigInteger)decimalValue;
Console.WriteLine(b);

Вышеописанные методы позволяют инициализировать BigInteger значением, которое лежит в границах соответствующего типа. Чтобы создать объект BigInteger, значение которого будет превышать границы любого интегрального типа можно воспользоваться одним из следующих способов:

  • Передать конструктору BigInteger массив типа byte. Этот конструктор может быть использован только для положительных значений:
byte[] byteArray = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
BigInteger newBigInt = new BigInteger(byteArray);
Console.WriteLine("The value of newBigInt is {0} (or 0x{0:x}).", newBigInt);
  • Конвертировать из строки с помощью методов Parse или TryParse:
string positiveString = "91389681247993671255432112000000";
string negativeString = "-90315837410896312071002088037140000";
BigInteger posBigInt = 0;
BigInteger negBigInt = 0;

try {
   posBigInt = BigInteger.Parse(positiveString);
   Console.WriteLine(posBigInt);
}
catch (FormatException)
{
   Console.WriteLine("Unable to convert the string '{0}' to a BigInteger value.", 
                     positiveString);
}

if (BigInteger.TryParse(negativeString, out negBigInt))
  Console.WriteLine(negBigInt);
else
   Console.WriteLine("Unable to convert the string '{0}' to a BigInteger value.", 
                      negativeString);
  • Использовать статический метод класса BigInteger для вычисления некоторого значения из числового выражения. Следующий код вычисляет куб максимального значения типа Int64:
BigInteger number = BigInteger.Pow(Int64.MaxValue, 3);
Console.WriteLine(number);

Неинициализированное значение BigInteger равно Zero.

Класс BigInteger перегружает основные математические операции, такие как сложение, вычитание, умножение, деление, унарный минус. Чтобы сравнить два объекта BigInteger можно использовать привычные операторы > или <. Так же как и другие числовые типы BigInteger поддерживает битовые операции и, или, исключающее или, и операции побитового сдвига. Помимом этого класс BigInteger поддерживает множество других математических операций с помощью статических методов класса. В их число входят следующие операции:

  • Abs (возвращает абсолютное значение для данного BigInteger)
  • Compare (выполняет сравнение двух BigInteger)
  • Divide (возвращает частное от деления двух BigInteger)
  • DivRem (возвращает частное и остаток от деления двух BigIntegers)
  • Equals (возвращает значение «истина», если два BigInteger имеют одинаковое значение)
  • GreatestCommonDivisor (возвращает наибольший общий делитель двух BigInteger)
  • ModPow (возвращает результат возведения одного BigInteger в степень другого BigInteger по модулю третьего; показатель степени не может быть отрицательным)
  • Pow (возвращает результат возведения одного BigInteger в степень другого; показатель степени не может быть отрицательным)
  • Remainder (возвращает остаток от деления одного BigInteger на другое)
  • Sign (возвращает знак BigInteger)

При работе с BigInteger важно помнить что тип BigInteger является неизменяемым(mutual). Это значит что при изменении значения объекта выделяется память под новый объект, туда копируется старый объект, и над ним производятся какие-либо действия. Старый объект уничтожается сборщиком мусора. Пример:

 

BigInteger number = BigInteger.Multiply(Int64.MaxValue, 3);
number++;
Console.WriteLine(number);

В этом коде значение переменной number увеличивается на единицу, что кажется тривиальной операцией. На самом деле CLR создаёт новый объект класса BigInteger и присваивает ему увеличенное значение. Точно так же ведёт себя тип string, который тоже является неизменяемым. Но поскольку BigInteger не имеет явной верхней или нижней границы при очень большом размере числа может возникнуть OutOfMemoryException. Чтобы проиллюстрировать это можно посчитать массив факториалов первых 50000 чисел:

 

using System;
using System.Numerics;
using System.Timers;

namespace BigIntegerTest
{
    class Program
    {
        static void calcFact(BigInteger a)
        {
            BigInteger[] array = new BigInteger[(int)a];

            BigInteger res = 1;
            for (int i = 2; i < a; i++)
            {
                res *= i;
                array[i] = res;
            }
        }

        static void Main(string[] args)
        {
            BigInteger a = new BigInteger(50000);
            try
            {
                calcFact(a);
            }
            catch (OutOfMemoryException e)
            {
                Console.WriteLine("Not enough memory");
            }
         }
    }
}

На моей машине с Win 7 x64 и 4 гигабайтами оперативной памяти возникает OutOfMemoryException. Чтобы отследить что происходит при этом я вопспользовался профайлером Visual Studui 2010. Чтобы его запустить нужно воспользоваться пунктом меню Analyze-> Launch Performance Wizard. Появится такое окошко:

  

Затем нужно выбрать свой проект для профилировки:

 

После анализа приложения профайлер выдаёт отчёт, в котором видно, какие функции потребляли больше всего памяти:

 

Соответственно в данном конктетном случае больше всего памяти вызывал метод op_Multiply, который судя по названию занимается перемножением двух больших чисел. При этом всего было выделено порядка 1,4 Гб:

 

Tags:

Comments

3/22/2010 9:39:07 PM #

trackback

Alexei Vasin | Новые возможности .NET 4.0: BigInteger

Thank you for submitting this cool story - Trackback from progg.ru

progg.ru

2/15/2012 3:51:36 AM #

Boob jobs before and after

I really enjoy studying on this web site , it contains good articles .

Boob jobs before and after United States

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.6.1.0
Theme by Extensive SEO