【问题标题】:How to 'define' a datatype in C++?如何在 C++ 中“定义”数据类型?
【发布时间】:2021-07-07 05:58:38
【问题描述】:

我正在解决一个 CodeChef 问题,该问题要求计算输入的阶乘。输入范围为100。这是问题的链接。

https://www.codechef.com/problems/FCTRL2

因此,有一种方法可以通过使用数组来解决 100 的阶乘问题,因为我使用了“插入排序”方法,但是出现了超出时间限制错误。所以 我想出了另一种方法,使用 unsigned long long int 数据类型。我定义了 int unsigned long long int 但它不起作用。如果你能帮忙解决,我会的。

#include <bits/stdc++.h> 
using namespace std;

#define int unsigned long long;
int main() {
    int t,n;
    cin>>t;
    if(1<=t<=100){
    while (t--) {
        cin>>n;
        if(1<=n<=100){
            int fact=1;
            for(int i=1;i<=n;i++){
                fact*=i;
            }
            cout<<fact<<endl;
        }
    }
}
    return 0;
}

【问题讨论】:

  • 为什么不直接用unsigned long long 替换int?不要#define 任何 c++ 关键字。
  • 100 的阶乘远大于 64 位。
  • 如果你想要一个更小的名字,使用 typedef,例如:typedef unsigned long long ull;
  • 请详细说明“不工作”
  • 查看这个链接geeksforgeeks.org/factorial-large-number - 一个很好的解释使用数组来保存不适合 64 位整数的巨大数字的数字

标签: c++


【解决方案1】:

100 的因子对于 64 位来说太大了,无论如何它都会溢出。关键是您应该实现自己的大数字类,或者使用现有的实现,例如 Boost 中的实现。

100 的阶乘有 158 位!

【讨论】:

    【解决方案2】:

    100! 对于64 位整数来说太大了。它有158 数字。您必须实现 BigInteger 库。希望@LightOj Judge 创建者@Jane Alom Jan 有一个很好的实现,你可以检查一下。我正在分享他的实现,您可以针对此问题进行修改和测试。

    #include <cstdio>
     
    #include <string>
     
    #include <algorithm>
     
    #include <iostream>
     
    using namespace std;
     
     
     
    struct Bigint {
     
        // representations and structures
     
        string a; // to store the digits
     
        int sign; // sign = -1 for negative numbers, sign = 1 otherwise
     
     
     
        // constructors
     
        Bigint() {} // default constructor
     
        Bigint( string b ) { (*this) = b; } // constructor for string
     
     
     
        // some helpful methods
     
        int size() { // returns number of digits
     
            return a.size();
     
        }
     
        Bigint inverseSign() { // changes the sign
     
            sign *= -1;
     
            return (*this);
     
        }
     
        Bigint normalize( int newSign ) { // removes leading 0, fixes sign
     
            for( int i = a.size() - 1; i > 0 && a[i] == '0'; i-- )
     
                a.erase(a.begin() + i);
     
            sign = ( a.size() == 1 && a[0] == '0' ) ? 1 : newSign;
     
            return (*this);
     
        }
     
     
     
        // assignment operator
     
        void operator = ( string b ) { // assigns a string to Bigint
     
            a = b[0] == '-' ? b.substr(1) : b;
     
            reverse( a.begin(), a.end() );
     
            this->normalize( b[0] == '-' ? -1 : 1 );
     
        }
     
     
     
        // conditional operators
     
        bool operator < ( const Bigint &b ) const { // less than operator
     
            if( sign != b.sign ) return sign < b.sign;
     
            if( a.size() != b.a.size() )
     
                return sign == 1 ? a.size() < b.a.size() : a.size() > b.a.size();
     
            for( int i = a.size() - 1; i >= 0; i-- ) if( a[i] != b.a[i] )
     
                return sign == 1 ? a[i] < b.a[i] : a[i] > b.a[i];
     
            return false;
     
        }
     
        bool operator == ( const Bigint &b ) const { // operator for equality
     
            return a == b.a && sign == b.sign;
     
        }
     
     
     
     
        // mathematical operators
     
        Bigint operator + ( Bigint b ) { // addition operator overloading
     
            if( sign != b.sign ) return (*this) - b.inverseSign();
     
            Bigint c;
     
            for(int i = 0, carry = 0; i<a.size() || i<b.size() || carry; i++ ) {
     
                carry+=(i<a.size() ? a[i]-48 : 0)+(i<b.a.size() ? b.a[i]-48 : 0);
     
                c.a += (carry % 10 + 48);
     
                carry /= 10;
     
            }
     
            return c.normalize(sign);
     
        }
     
        Bigint operator - ( Bigint b ) { // subtraction operator overloading
     
            if( sign != b.sign ) return (*this) + b.inverseSign();
     
            int s = sign; sign = b.sign = 1;
     
            if( (*this) < b ) return ((b - (*this)).inverseSign()).normalize(-s);
     
            Bigint c;
     
            for( int i = 0, borrow = 0; i < a.size(); i++ ) {
     
                borrow = a[i] - borrow - (i < b.size() ? b.a[i] : 48);
     
                c.a += borrow >= 0 ? borrow + 48 : borrow + 58;
     
                borrow = borrow >= 0 ? 0 : 1;
     
            }
     
            return c.normalize(s);
     
        }
     
        Bigint operator * ( Bigint b ) { // multiplication operator overloading
     
            Bigint c("0");
     
            for( int i = 0, k = a[i] - 48; i < a.size(); i++, k = a[i] - 48 ) {
     
                while(k--) c = c + b; // ith digit is k, so, we add k times
     
                b.a.insert(b.a.begin(), '0'); // multiplied by 10
     
            }
     
            return c.normalize(sign * b.sign);
     
        }
     
        Bigint operator / ( Bigint b ) { // division operator overloading
     
            if( b.size() == 1 && b.a[0] == '0' ) b.a[0] /= ( b.a[0] - 48 );
     
            Bigint c("0"), d;
     
            for( int j = 0; j < a.size(); j++ ) d.a += "0";
     
            int dSign = sign * b.sign; b.sign = 1;
     
            for( int i = a.size() - 1; i >= 0; i-- ) {
     
                c.a.insert( c.a.begin(), '0');
     
                c = c + a.substr( i, 1 );
     
                while( !( c < b ) ) c = c - b, d.a[i]++;
     
            }
     
            return d.normalize(dSign);
     
        }
     
        Bigint operator % ( Bigint b ) { // modulo operator overloading
     
            if( b.size() == 1 && b.a[0] == '0' ) b.a[0] /= ( b.a[0] - 48 );
     
            Bigint c("0");
     
            b.sign = 1;
     
            for( int i = a.size() - 1; i >= 0; i-- ) {
     
                c.a.insert( c.a.begin(), '0');
     
                c = c + a.substr( i, 1 );
     
                while( !( c < b ) ) c = c - b;
     
            }
     
            return c.normalize(sign);
     
        }
     
     
     
     
        // output method
     
        void print() {
     
            if( sign == -1 ) putchar('-');
     
            for( int i = a.size() - 1; i >= 0; i-- ) putchar(a[i]);
     
        }
     
    };
     
     
     
    int main() {
     
        Bigint a, b, c; // declared some Bigint variables
     
     
     
        /////////////////////////
     
        // taking Bigint input //
     
        /////////////////////////
     
        string input; // string to take input
     
     
     
        cin >> input; // take the Big integer as string
     
        a = input; // assign the string to Bigint a
     
     
     
        cin >> input; // take the Big integer as string
     
        b = input; // assign the string to Bigint b
     
     
     
        //////////////////////////////////
     
        // Using mathematical operators //
     
        //////////////////////////////////
     
     
     
        c = a + b; // adding a and b
     
        c.print(); // printing the Bigint
     
        puts(""); // newline
     
     
     
        c = a - b; // subtracting b from a
     
        c.print(); // printing the Bigint
     
        puts(""); // newline
     
     
     
        c = a * b; // multiplying a and b
     
        c.print(); // printing the Bigint
     
        puts(""); // newline
     
     
     
        c = a / b; // dividing a by b
     
        c.print(); // printing the Bigint
     
        puts(""); // newline
     
     
     
        c = a % b; // a modulo b
     
        c.print(); // printing the Bigint
     
        puts(""); // newline
     
     
     
        /////////////////////////////////
     
        // Using conditional operators //
     
        /////////////////////////////////
     
     
     
        if( a == b ) puts("equal"); // checking equality
     
        else puts("not equal");
     
     
     
        if( a < b ) puts("a is smaller than b"); // checking less than operator
     
     
     
        return 0;
     
    }
    

    由于问题的源限制为 2000 字节,因此添加洞 BigInteger 库将超过源限制。

    所以这里只能进行字符串乘法。

    下面给出了一个干净的乘法方法,使用C++

    #include<bits/stdc++.h>
    using namespace std;
    int main(){
        int t;
        cin >> t;
        while(t--){
            vector<int> arr;
            int n;
            cin >> n;
    
            arr.push_back(1);
            int carry = 0;
    
            for(int i = 2; i <= n; i++){
                vector<int> t;
                for(int j = arr.size() - 1; j >= 0; j--){
                    int r = arr[j] * i + carry;
                    carry = r / 10;
                    t.push_back(r % 10);
                }
                while(carry){
                    t.push_back(carry % 10);
                    carry /= 10;
                }
                reverse(t.begin(), t.end());
                arr = t;
            }
            for(auto el : arr){
                cout << el;
            }
            cout << endl;
        }
        return 0;
    }
    

    输入

    2
    10
    100
    

    输出

    3628800
    93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
    

    还添加了一个简单的python 实现

    test = int(input())
    
    for i in range(0, test):
        n = int(input())
        res = 1
        for j in range(2, n + 1):
            res = res * j
        print(res)
    

    【讨论】:

      【解决方案3】:

      已经有 3 天的问题了,但无论如何。

      解决方案是一项相当简单的任务。我们可以像在一张纸上那样做。我们使用std::vector 的数字来保存号码。因为结果对于 unsigned long long 来说已经太大了 22!。

      答案将是准确的。而且代码短小精悍。

      使用这种方法,计算很简单。我什至不知道该进一步解释什么。

      请小心运行时。对于大数字来说,这将是非常长的。如果速度是个问题,那么只使用原始的 BigInt 标头库。

      请看代码:

      #include <iostream>
      #include <vector>
      
      int main()
      {
          std::cout << "Calculate n!   Enter n (max 10000): ";
          if (unsigned int input{}; (std::cin >> input) && (input <= 10000)) {
      
              // Here we store the resulting number as single digits
              std::vector<unsigned int> result(3000, 0);  // Magic number. Is big enough for 100000!
              result.back() = 1;                          // Start calculation with 1 (from right to left)
      
              // Multiply up to the given input value
              for (unsigned int count = 2; count <= input; count++)
              {
                  unsigned int sum{}, remainder{};
                  unsigned int i = result.size() - 1;     // Calculate from right to left
                  while (i > 0)
                  {
                      // Simple multiplication like on a piece of paper
                      sum = result[i] * count + remainder;
                      result[i--] = sum % 10;
                      remainder = sum / 10;
                  }
              }
              // Show output. Supporess leading zeroes
              bool showZeros{ false };
              for (const unsigned int i : result) {
                  if ((i != 0) || showZeros) {
                      std::cout << i;
                      showZeros = true;
                  }
              }
          }
          else std::cerr << "\nError: Wrong input.";
      }
      

      使用 Microsoft Visual Studio Community 2019 版本 16.8.2 开发和测试。

      使用 clang11.0 和 gcc10.2 额外编译和测试

      语言:C++17

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-31
        • 2019-05-30
        • 2018-07-05
        • 1970-01-01
        • 2014-02-13
        • 2012-03-28
        • 1970-01-01
        相关资源
        最近更新 更多