Покритикуйте тестовой задание про факториал.
От: zayats  
Дата: 31.08.12 07:17
Оценка:
Предыстория такова. Хотел на С#-юниора устроиться, проходил телефонное интервью. И среди прочего интервьюер спросил "а вот если тебе надо посчитать точный факториал некоего большого числа, например, 2000, как будешь делать?". Я ответил, что мол, напишу класс для работы с целыми числами любой длины и потом факториал с ними посчитаю. О, говорит, он, круто, давай напиши такое тестовое задание, присылай нам и на собеседование приходи, там обсудим. Вот я и написал нижеследующее, пришёл на собеседование, вроде поговорили, обсудили. И потом всё стихло, ни звонков, ничего. Сейчас-то я работаю в другом месте, всё ок. Но интересно стало, это насколько плох мой код, из-за него меня не взяли, или уже на собеседовании облажался, или просто не понравился.
Покритикуйте, пожалуйста. Что класс недоделан я знаю, вчастности нет оператора -. Ну и си-стиль наверное прёт. Но главное мне было нужно факториал сделать. Считает вроде правильно, по интернет-калькулятору факториалов проверял.
Заранее спасибо.

using System;
using System.Collections.Generic;

namespace bigint
{
    class BigInt
    {
        public BigInt() { }

        public BigInt(int val)
        {
            isPos_ = (val >= 0);
            int v = Math.Abs(val);
            while (v > 0)
            {
                val_.Add((byte)(v % 10));
                v /= 10;
            }
        }

        public BigInt(BigInt val)
        {
            isPos_ = val.isPos_;
            val_.AddRange(val.val_);
        }

        public static BigInt operator+(BigInt val1, BigInt val2)
        {
            if (val1.isPos_ == val2.isPos_)
                return Add(val1, val2);
            else
                return Deduct(val1, val2);
        }

        public static BigInt operator+(BigInt val1, int val2)
        {
            return val1 + new BigInt(val2);
        }

        public static BigInt operator*(BigInt val, int n)
        {
            BigInt retVal = new BigInt() { isPos_ = n >= 0 ? val.isPos_ : !val.isPos_};
            int absN = Math.Abs(n);
            if (absN == 0)
                return retVal;
            if (absN == 1)
                return retVal + val;

            int sqrt = (int)Math.Floor(Math.Sqrt(absN));
            BigInt tmp = new BigInt(val);
            
            for (int i = 0; i < sqrt - 1; ++i)
                tmp = tmp + val;

            for (int i = 0; i < absN / sqrt; ++i)
                retVal = retVal + tmp;

            for (int i = 0; i < absN % sqrt; ++i)
                retVal = retVal + val;

            return retVal;
        }

        public static BigInt Factorial(int val)
        {
            BigInt retVal = new BigInt(1);
            for (int i = 2; i <= val; i++)
                retVal = retVal * i;
            return retVal;
        }

        private static Dictionary<int, BigInt> factsCache_ = new Dictionary<int, BigInt>();
        public static BigInt FactorialWithCache(int val)
        {
            if (val <= 1)
                return new BigInt(1);
            if (!factsCache_.ContainsKey(val))
                factsCache_.Add(val, FactorialWithCache(val - 1) * val);
            return factsCache_[val];
        }

        public string GetValue(bool inExpFormat = false)
        {
            string retVal = "";
            if (val_.Count == 0)
                return "0";

            if (!inExpFormat)
            {
                foreach (var n in val_)
                    retVal = n.ToString() + retVal;
                if (!isPos_)
                    retVal = "-" + retVal;
            }
            else
            {
                for (int i = Math.Max(val_.Count - 9, 0); i < val_.Count; ++i)
                {
                    if (i == val_.Count - 1)
                        retVal = "." + retVal;
                    retVal = val_[i] + retVal;
                }
                retVal += " x 10^" + (val_.Count - 1).ToString();
                if (!isPos_)
                    retVal = "-" + retVal;
            }
            return retVal;
        }

        private static BigInt Add(BigInt val1, BigInt val2)
        {
            BigInt retVal = new BigInt(val1) { isPos_ = val1.isPos_ };

            int minSize = Math.Min(retVal.val_.Count, val2.val_.Count);
            bool trans = false;
            for (int i = 0; i < minSize; ++i)
            {
                int n = retVal.val_[i] + val2.val_[i];
                if (trans)
                    ++n;

                trans = (n > 9);

                retVal.val_[i] = (byte)(n % 10);
            }
            if (retVal.val_.Count < val2.val_.Count)
                for (int i = minSize; i < val2.val_.Count; ++i)
                    retVal.val_.Add(val2.val_[i]);

            if (trans)
            {
                int i = minSize;
                while (trans)
                {
                    if (retVal.val_.Count == i)
                    {
                        retVal.val_.Add(1);
                        trans = false;
                    }
                    else
                    {
                        int n = retVal.val_[i] + 1;

                        trans = (n > 9);

                        retVal.val_[i] = (byte)(n % 10);
                    }
                    ++i;
                }
            }
            return retVal;
        }

        private static BigInt Deduct(BigInt val1, BigInt val2)
        {
            bool isGrt = isGreaterOrEqual(val1.val_, val2.val_);
            BigInt retVal = new BigInt(isGrt ? val1 : val2) { isPos_ = isGrt ? val1.isPos_ : !val1.isPos_ };

            int minSize = Math.Min(val1.val_.Count, val2.val_.Count);
            bool trans = false;
            for (int i = 0; i < minSize; ++i)
            {
                int n = retVal.val_[i] - (isGrt ? val2.val_[i] : val1.val_[i]);
                if (trans)
                    --n;
                
                trans = (n < 0);

                if (n < 0)
                    n += 10;

                retVal.val_[i] = (byte)(n % 10);
            }

            int ii = retVal.val_.Count - 1;
            while (ii >= 0 && retVal.val_[ii] == 0)
            {
                retVal.val_.RemoveAt(ii);
                --ii;
            }
            if (retVal.val_.Count == 0)
                retVal.isPos_ = false;
            return retVal;
        }

        private static bool isGreaterOrEqual(List<byte> l1, List<byte> l2)
        {
            if (l1.Count > l2.Count)
                return true;

            if (l1.Count < l2.Count)
                return false;

            if (l1.Count == 0)
                return true;

            for (int i = l1.Count -1; i >= 0; --i)
            {
                if (l1[i] > l2[i])
                    return true;
                if (l1[i] < l2[i])
                    return false;
            }
            return true;
        }

        private List<byte> val_ = new List<byte>();
        private bool isPos_ = true;
    }
}

Использование:
static void Main(string[] args)
{
     Console.SetOut(new System.IO.StreamWriter("fact.log", true));
            
     for (int i = 0; i <= 5000; ++i)
         Console.WriteLine(string.Format("{0:00000}!: {1}", i, BigInt.FactorialWithCache(i).GetValue()));
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.