比较两个因子而不计算

时间:2015-11-25 12:27:45

标签: c# .net decimal factorial

有没有办法比较两个数字中哪个阶乘数更大而不计算?
方案是我正在创建一个c#控制台应用程序,它需要两个因子输入,如

123!!!!!!
456!!!  

我想做的就是比较哪个因子值大于其他因素,我所做的代码是

try
{
    string st = Console.ReadLine();
    Int64 factCount = 0;
    while (st.Contains('!'))
    {
       factCount = st.Where(w => w == '!').Count();
       st = st.Replace('!', ' ');

    };
    decimal result = 1 ;
    for (Int64 j = 0; j < factCount; j++)
    {
        UInt64 num = Convert.ToUInt64(st.Trim());
        for (UInt64 x = num; x > 0; x--)
        {
            result = result * x;
        }
    }
    if (factCount == 0)
    {
        result = Convert.ToUInt64(st.Trim());
    }


    string st2 = Console.ReadLine();
    Int64 factCount2 = 0;
    while (st2.Contains('!'))
    {
        factCount2 = st2.Where(w => w == '!').Count();
        st2 = st2.Replace('!', ' ');
    };
    decimal result2 = 1;
    for (Int64 j = 0; j < factCount2; j++)
    {
        UInt64 num = Convert.ToUInt64(st.Trim());
        for (UInt64 x = num; x > 0; x--)
        {
            result2 = result2 * x;
        }
    }
    if (factCount2 == 0)
    {
        result2 = Convert.ToUInt64(st2.Trim());
    }

    if (result == result2)
    {
        Console.WriteLine("x=y");
    }
    else if (result < result2)
    {
        Console.WriteLine("x<y");
    }
    else if (result > result2)
    {
        Console.WriteLine("x>y");
    }
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    Console.ReadLine();
}

但我得到的错误是 值对于十进制来说太大或太小
我理解错误,但有没有办法做到这一点

请建议是否有任何其他数据类型可以容纳大于十进制的值,或者是否有其他方法可以比较这些因子

在实施@Bathsheba建议后,我改变了一些代码

    string st = Console.ReadLine();
    int factCount = 0;
    while (st.Contains('!'))
    {
       factCount = st.Where(w => w == '!').Count();
       st = st.Replace('!', ' ');

    };

    string st2 = Console.ReadLine();
    int factCount2 = 0;
    while (st2.Contains('!'))
    {
        factCount2 = st2.Where(w => w == '!').Count();
        st2 = st2.Replace('!', ' ');
    };

    int resultFactCount = factCount - factCount2;
    decimal result = 1;
    decimal result2 = 1;

    if (resultFactCount > 0)
    {

        for (Int64 j = 0; j < resultFactCount; j++)
        {
            UInt64 num = Convert.ToUInt64(st.Trim());
            for (UInt64 x = num; x > 0; x--)
            {
                result = result * x;
            }
        }
        if (factCount == 0)
        {
            result = Convert.ToUInt64(st.Trim());
        }
        UInt64 num1 = Convert.ToUInt64(st.Trim());
        if (result == num1)
        {
            Console.WriteLine("x=y");
        }
        else if (result < num1)
        {
            Console.WriteLine("x<y");
        }
        else if (result > num1)
        {
            Console.WriteLine("x>y");
        }
    }
    else
    {
        int resultFactCount1 = System.Math.Abs(resultFactCount);
        for (Int64 j = 0; j < resultFactCount1; j++)
        {
            UInt64 num = Convert.ToUInt64(st.Trim());
            for (UInt64 x = num; x > 0; x--)
            {
                result2 = result2 * x;
            }
        }
        if (factCount2 == 0)
        {
            result2 = Convert.ToUInt64(st2.Trim());
        }
        UInt64 num1 = Convert.ToUInt64(st.Trim());

        if (result2 == num1)
        {
            Console.WriteLine("x=y");
        }
        else if (result2 < num1)
        {
            Console.WriteLine("x<y");
        }
        else if (result2 > num1)
        {
            Console.WriteLine("x>y");
        }
    }   

很抱歉,但仍然是123 !!!是如此巨大,以至于我得到了同样的错误

  

传统上m!!...! n ! s表示m(m-n)(m-2n)....但是此处被视为(...((m!)!)!...)!
  Alec的注释,是的,我知道,这是一个不幸的符号,但是你看到传统的定义比OP想要的更有用(在组合学中,因子来自的地方)。   我会把它放在评论中,但它会被其他人黯然失色,这非常重要。

8 个答案:

答案 0 :(得分:52)

此处,a!!定义为(a!)!

123!!!!!!绝对是巨大的。我认为你需要更多的粒子而不是宇宙中的粒子,如果你用墨水写下来的话。

因此,您无法直接比较这些数字。我推测没有一个数字类可以做到这一点。

许多倍数都是相似的,所以你可以取消它们。另请注意,尾随123!!!!!! / 456!!!将取消。这是因为x> y暗示,并暗示x! &GT; Y!其中x和y是正整数。

最终,您将达到可以将其评估为小于或大于1的点,从而产生您的答案。

我可以告诉你 on inspection !123!!!!!!大于123!!!而更大。

答案 1 :(得分:22)

与其他答案不同,你可以做到而不做任何近似。

这是:

123 !!!!!! > 456 !!! 

实际上意味着

123 !!!!! > 456 !!
123 !!!! > 456 ! 

以及

123 !!! > 456  

所以你只需要证明上述内容。这很简单,因为你至少有一个操作数适合UInt64

所以这应该给你这样的东西:

public class Program
{
    static bool LeftIsGreaterThanRightSide(UInt64 leftSide, int leftSidefactCount, UInt64 rightSide)
    {
        try
        {
            checked // for the OverflowException
            {
                UInt64 input2 = leftSide;
                int factCount = leftSidefactCount;
                UInt64 result = 1;

                for (Int64 j = 0; j < factCount; j++)
                {
                    UInt64 num = input2;
                    for (UInt64 x = num; x > 0; x--)
                    {
                        result = result * x;
                    }
                }

                // None of the operand are great or equal than UInt64.MaxValue
                // So let's compare the result normaly
                return result > rightSide; 
            }
        }
        catch (OverflowException)
        {
            // leftSide overflowed, rightSide is a representable UInt64 so leftSide > rightSide ; 
            return true; 
        }
    }


    static void Main()
    {
        String input1 = Console.ReadLine();
        String input2 = Console.ReadLine();

        int fact1Count = input1.Count(c => c == '!');
        int fact2Count = input2.Count(c => c == '!');

        UInt64 x = Convert.ToUInt64(input1.Replace("!", String.Empty).Trim());
        UInt64 y = Convert.ToUInt64(input2.Replace("!", String.Empty).Trim());

        x = x == 0 ? 1 : x ; // Handling 0 !
        y = y == 0 ? 1 : y; 

        if (fact1Count > fact2Count)
        {
            fact1Count = fact1Count - fact2Count;
            Console.WriteLine(LeftIsGreaterThanRightSide(x, fact1Count, y) ? "x > y" : "x <= y");
        }
        else
        {
            fact2Count = fact2Count - fact1Count;
            Console.WriteLine(LeftIsGreaterThanRightSide(y, fact2Count, x) ? "y > x" : "y <= x");
        }

        Console.ReadLine();
    }


}

答案 2 :(得分:14)

对于给定的数字,假设456!!!表示((456!)!)!我们有

  123!!!!!! == (123!!!)!!!

  123!!! >>> 456 // >>> stands for "much, much...much larger", ">>" is not enough 

甚至123!1.2e205)远远大于456

要估算阶乘的实际值,让我们使用斯特林近似值

https://en.wikipedia.org/wiki/Stirling%27s_approximation

  ln(n!) == n * ln(n) - n
  lg(n!) == ln(n!)/ln(10) == n * ln(n) / ln(10) - n / ln(10) == n * lg(n) - n / ln(10)
      n! == n ** n / exp(n)

所以((456!)!)!是关于

  lg(456!)       == 1014
  lg((456!)!)    == 1e1014 * 1014- 1e1014/ln(10) == 1e1017
  lg(((456!)!)!) == 1e(1e1017) 
     ((456!)!)!  == 1e(1e(1e1017))

极其庞大的数字(注意三次取幂),这就是为什么不能表示为天真的BigInteger值。

答案 3 :(得分:6)

这应该很简单:

正如其他人所说,你可以删除所有常见的“!”因为x > y <==> x! > y!

你的程序基本上必须证明阶乘(123 !!!)大于普通数字。您可以通过快速退出循环来解决此问题。在计算阶乘时,您可以在产品大于456时立即返回,因为阶乘总是随着额外的迭代而增长。

// While string parsing check if one number equals 0 and has at least
// one "!" - if yes set its value to 1 ( because 0! = 1! = 1 )

int x = 123;
int y = 456;
int numberOfFactorials = 3;

try
{
    for( int i = 0; i < numberOfFactorials; ++i )
    {
        for ( int j = x-1; j > 0; --j )
        {
            x *= j;
            // This quick exit will return after one iteration
            // because 123*122 > 456
            if ( x > y ) return "x is bigger than y";
        }
    }

    return x == y ? "gosh they are the same!"
                  : "x is smaller than y";
}
catch( OverflowException e )
{
   return "x Overflowed so it is bigger than y!";
}

如果要为输入参数解析更大的数字,也可以将BigInteger与此方法一起使用。

答案 4 :(得分:2)

正如其他人所说,123 !!!!!!和456 !!!只有太大才能由计算机代表,并且x!! <=> y!类型的比较会缩减为x! <=> y

一旦达到最小可能的!(从字符串中删除它们),就可以评估操作数。其中一个数字将是一个公共整数(无因子),所以这里没有工作。另一个将至少有一个阶乘,否则比较是微不足道的。

假设比较为x! <=> y(一个因子)。如果x >= y,您就完成了。如果x < y,请评估x!并进行比较。

假设比较为x!! <=> y(两个因子)。制表最小值:

1!! = 1! = 1
2!! = 2! = 2
3!! = 6! = 720
4!! = 24! = 620,448,401,733,239,439,360,000
5!! = 120! = about 6.6895 * 10^198
6!! = 720! = about 2.6012 * 10^1746

因此,对于任何yx > 4将导致x!! > y。对于x <= 4,请评估x!!并进行比较。

如需更多阶乘,请记住x!!! = (x!)!!,评估x!,并使用上述步骤。

答案 5 :(得分:1)

BigInteger类型可以处理大整数。但对你的例子来说还不够大。

可以将小因子考虑到其素因子中,而不必首先计算因子本身,并且可以取消相同的因子。

您也可以按照建议by Leherenn above取消跟踪!,因为123!大于456,(123 !!!)!!!也将大于(456)!!!。

答案 6 :(得分:0)

让我们定义一个类型来表示重复阶乘的运算:

public struct RepeatedFactorial
{
  private readonly int _baseNumber;
  private readonly int _repeats;
  public int BaseNumber
  {
    get { return _baseNumber; }
  }
  public int Repeats {
    get { return _repeats; }
  }
  public RepeatedFactorial(int baseNumber, int repeats)
  {
    if (baseNumber < 0 || repeats < 0) throw new ArgumentOutOfRangeException();
    _baseNumber = baseNumber;
    _repeats = repeats;
  }
}

现在,如果我们实施IComparable<Factorial>,我们就能找到想要的答案。

public int CompareTo(RepeatedFactorial other)
{
  // ?
}

让我们先考虑一些较简单的案例。

public int CompareTo(RepeatedFactorial other)
{
  if (BaseNumber == 0)
  {
    // If Repeats is zero the value of this is zero, otherwise
    // this is the same as a value with BaseNumber == 1 and no factorials.
    // So delegate to the handling of that case.
    if (Repeats == 0) return other.BaseNumber == 0 && other.Repeats == 0 ? 0 : -1;
    return new RepeatedFactorial(1, 0).CompareTo(other);
  }
  if (other.BaseNumber == 0)
    // Likewise
    return other.Repeats == 0 ? 1 : CompareTo(new RepeatedFactorial (1, 0));
  if (Repeats == other.Repeats)
    // X < Y == X! < Y!. X > Y == X! > Y! And so on.
    return BaseNumber.CompareTo(other.BaseNumber);
  ???
}

好的,唯一未处理的案例是this的重复因子少于other,反之亦然。让我们将其中一个案例转换为另一个案例,以便我们更少地处理:

public int CompareTo(RepeatedFactorial other)
{
  if (BaseNumber == 0)
  {
    // If Repeats is zero the value of this is zero, otherwise
    // this is the same as a value with BaseNumber == 1 and no factorials.
    // So delegate to the handling of that case.
    if (Repeats == 0) return other.BaseNumber == 0 && other.Repeats == 0 ? 0 : -1;
    return new RepeatedFactorial(1, 0).CompareTo(other);
  }
  if (other.BaseNumber == 0)
    // Likewise
    return other.Repeats == 0 ? 1 : CompareTo(new RepeatedFactorial (1, 0));
  if (Repeats == other.Repeats)
    // X < Y == X! < Y!. X > Y == X! > Y! And so on.
    return BaseNumber.CompareTo(other.BaseNumber);
  if (Repeats > other.Repeats)
    return -other.CompareTo(this);
  ???
}

现在我们只需要担心this重复次数少于other。由于X> Y暗示X! &GT; Y!等等我们可以将这个问题减少到我们知道this零重复的地方:

public int CompareTo(RepeatedFactorial other)
{
  if (BaseNumber == 0)
  {
    // If Repeats is zero the value of this is zero, otherwise
    // this is the same as a value with BaseNumber == 1 and no factorials.
    // So delegate to the handling of that case.
    if (Repeats == 0) return other.BaseNumber == 0 && other.Repeats == 0 ? 0 : -1;
    return new RepeatedFactorial(1, 0).CompareTo(other);
  }
  if (other.BaseNumber == 0)
    // Likewise
      return other.Repeats == 0 ? 1 : CompareTo(new RepeatedFactorial (1, 0));
  if (Repeats == other.Repeats)
    // X < Y == X! < Y!. X > Y == X! > Y! And so on.
    return BaseNumber.CompareTo(other.BaseNumber);
  if (Repeats > other.Repeats)
    return -other.CompareTo(this);
  if (Repeats != 0)
    return new RepeatedFactorial(BaseNumber, 0).CompareTo(new RepeatedFactorial(other.BaseNumber, other.Repeats - Repeats);
  ???
}

现在,我们需要this.BaseNumberother.BaseNumber的比较,并应用适当数量的因子。显然,如果other.BaseNumber大于12,那么从13开始!大于int.MaxValue必须大于this.BaseNumber

public int CompareTo(RepeatedFactorial other)
{
  if (BaseNumber == 0)
  {
    // If Repeats is zero the value of this is zero, otherwise
    // this is the same as a value with BaseNumber == 1 and no factorials.
    // So delegate to the handling of that case.
    if (Repeats == 0) return other.BaseNumber == 0 && other.Repeats == 0 ? 0 : -1;
    return new RepeatedFactorial(1, 0).CompareTo(other);
  }
  if (other.BaseNumber == 0)
    // Likewise
    return other.Repeats == 0 ? 1 : CompareTo(new RepeatedFactorial (1, 0));
  if (Repeats == other.Repeats)
    // X < Y == X! < Y!. X > Y == X! > Y! And so on.
    return BaseNumber.CompareTo(other.BaseNumber);
  if (Repeats > other.Repeats)
    return -other.CompareTo(this);
  if (Repeats != 0)
    return new RepeatedFactorial(BaseNumber, 0).CompareTo(new RepeatedFactorial(other.BaseNumber, other.Repeats - Repeats);
  if (other.BaseNumber > 12)
    return -1; // this is less than other
  ???
}

现在我们离开计算实际数字了。但是,如果在阶乘循环开始时我们有13或更高,那么我们可以通过与上面相同的逻辑返回-1。否则,如果我们最终得到的数字大于this.BaseNumber,我们也可以返回-1

public int CompareTo(RepeatedFactorial other)
{
    if (BaseNumber == 0)
    {
      // If Repeats is zero the value of this is zero, otherwise
      // this is the same as a value with BaseNumber == 1 and no factorials.
      // So delegate to the handling of that case.
      if (Repeats == 0) return other.BaseNumber == 0 && other.Repeats == 0 ? 0 : -1;
      return new RepeatedFactorial(1, 0).CompareTo(other);
    }
    if (other.BaseNumber == 0)
      // Likewise
      return other.Repeats == 0 ? 1 : CompareTo(new RepeatedFactorial (1, 0));
  if (Repeats == other.Repeats)
    // X < Y == X! < Y!. X > Y == X! > Y! And so on.
    return BaseNumber.CompareTo(other.BaseNumber);
  if (Repeats > other.Repeats)
    return -other.CompareTo(this);
  if (Repeats != 0)
    return new RepeatedFactorial(BaseNumber, 0).CompareTo(new RepeatedFactorial(other.BaseNumber, other.Repeats - Repeats);
  int accum = other.BaseNumber;
  for (int rep = 0; rep != other.Repeats; ++rep)
  {
    if (accum > 12 || accum > BaseNumber) return -1;
    for (int mult = accum - 1; mult > 1; --mult)
    accum *= mult;
  }
  return BaseNumber.CompareTo(accum);
}

因此我们得到了答案,而且永远不必计算大于12的因子!

全部放在一起:

public struct RepeatedFactorial : IComparable<RepeatedFactorial>
{
  private readonly int _baseNumber;
  private readonly int _repeats;
  public int BaseNumber
  {
    get { return _baseNumber; }
  }
  public int Repeats {
    get { return _repeats; }
  }
  public RepeatedFactorial(int baseNumber, int repeats)
  {
    if (baseNumber < 0 || repeats < 0) throw new ArgumentOutOfRangeException();
    _baseNumber = baseNumber;
    _repeats = repeats;
  }
  public int CompareTo(RepeatedFactorial other)
  {
    if (BaseNumber == 0)
    {
      // If Repeats is zero the value of this is zero, otherwise
      // this is the same as a value with BaseNumber == 1 and no factorials.
      // So delegate to the handling of that case.
      if (Repeats == 0) return other.BaseNumber == 0 && other.Repeats == 0 ? 0 : -1;
      return new RepeatedFactorial(1, 0).CompareTo(other);
    }
    if (other.BaseNumber == 0)
      // Likewise
      return other.Repeats == 0 ? 1 : CompareTo(new RepeatedFactorial (1, 0));
    if (Repeats == other.Repeats)
      // X < Y == X! < Y!. X > Y == X! > Y! And so on.
      return BaseNumber.CompareTo(other.BaseNumber);
    if (Repeats > other.Repeats)
      return -other.CompareTo(this);
    if (Repeats != 0)
      return new RepeatedFactorial(BaseNumber, 0).CompareTo(new RepeatedFactorial(other.BaseNumber, other.Repeats - Repeats));
    int accum = other.BaseNumber;
    for (int rep = 0; rep != other.Repeats; ++rep)
    {
      if (accum > 12 || accum > BaseNumber) return -1;
      for (int mult = accum - 1; mult > 1; --mult)
        accum *= mult;
    }
    return BaseNumber.CompareTo(accum);
  }
}

编辑:

我刚刚意识到你实际上在你的问题中使用64位值。这很容易适应,我们仍然不必超过计算20!

public struct RepeatedFactorial : IComparable<RepeatedFactorial>
{
  private readonly ulong _baseNumber;
  private readonly long _repeats;
  public ulong BaseNumber
  {
    get { return _baseNumber; }
  }
  public long Repeats {
    get { return _repeats; }
  }
  public RepeatedFactorial(ulong baseNumber, long repeats)
  {
    if (baseNumber < 0 || repeats < 0) throw new ArgumentOutOfRangeException();
    _baseNumber = baseNumber;
    _repeats = repeats;
  }
  public int CompareTo(RepeatedFactorial other)
  {
    if (BaseNumber == 0)
      // This is the same as a value with BaseNumber == 1 and no factorials.
      // So delegate to the handling of that case.
      return new RepeatedFactorial(1, 0).CompareTo(other);
    if (other.BaseNumber == 0)
      // Likewise
      return CompareTo(new RepeatedFactorial (1, 0));
    if (Repeats == other.Repeats)
      // X < Y == X! < Y!. X > Y == X! > Y! And so on.
      return BaseNumber.CompareTo(other.BaseNumber);
    if (Repeats > other.Repeats)
      return -other.CompareTo(this);
    if (Repeats != 0)
      return new RepeatedFactorial(BaseNumber, 0).CompareTo(new RepeatedFactorial(other.BaseNumber, other.Repeats - Repeats));
    ulong accum = other.BaseNumber;
    for (long rep = 0; rep != other.Repeats; ++rep)
    {
      if (accum > 20 || accum > BaseNumber) return -1;
      for (ulong mult = accum - 1; mult > 1; --mult)
        accum *= mult;
    }
    return BaseNumber.CompareTo(accum);
  }
}

答案 7 :(得分:0)

对于正整数,如果双方都有相同数量的阶乘,那么就像比较两个数字一样简单

123!!!!
456!!!!

456 > 123
456!!!! > 123!!!!

否则,比较两个因子,归结为

123!!!!!!
456!!!

(123!!!)!!!
(456!!!)

123!!!
456

此时我们将尝试逐一评估因子,直到我们超过另一个数字。

由于另一个数字是一个可以存储在变量中的数字,这意味着我们已经计算出一个更高的数字天气,或者已经遇到溢出异常,那么它是一个更大的数字,否则它是一个更小的数字。 / p>

以下是伪造代码,而非实际代码:

int max_factorial (int x, int x_fact, int y, int y_fact)
{
    int A=1,B=1,F=0,product=1,sum=0;

    if (x_fact == y_fact) return (x>y?x:y);

    if (x_fact > y_fact)
    {
        A = x; B = y; F = x_fact-y_fact;
    }
    else
    {
        A = y; B = x; F = y_fact-x_fact;
    }

    for (int k=0; k<F; k++)
    {
        try
        {
            for (int i=1; i<A; i++)
            {
                // multiplication in terms of addition
                // P * i = P + P + .. P } i times
                sum = 0; for (int p=0; p<i; p++) sum += product;
                product = product + sum;
                if (product > B) return A;
            }
        }
        catch (OverflowException e)
        {
            return A;
        }
    }

    return B;
}