c++ 将阶乘序列显示为字符串

epggiuax  于 2023-03-14  发布在  其他
关注(0)|答案(3)|浏览(124)

//下面是我的代码,用来查找一个数的阶乘:

int get_factorial(int num)
{
   auto sum = 1;
   while(num > 0)
   {
       sum = sum * num;
       num--;
   }

   return sum;
}

//这个函数可以给予我阶乘,但是我的赋值语句要我返回一个字符串。所以如果我的参数是5,而不是像我的代码现在那样返回120,我需要它返回一个字符串,表示“1x 2x 3x 4x 5 = 120”。“5x 4x 3x 2x 1 = 120”也应该可以。
我不知道从哪里开始,我想也许可以创建一个字符串,然后在它通过循环时附加每个和,但我不知道如何做到这一点。

5rgfhyps

5rgfhyps1#

这个作业对于像你我这样的初学者来说并不容易。:)
我可以建议下面的演示程序中显示的解决方案。

#include <iostream>
#include <string>

std::string get_factorial( unsigned int n )
{
    std::string result;
    unsigned long long factorial = 1;

    while (n > 1)
    {
        result += std::to_string( n ) + 'x';
        factorial *= n--;
    }

    return result + std::to_string( n ) + " = " + std::to_string( factorial );
}

int main()
{
    for (unsigned int i = 0; i < 10; i++)
    {
        std::cout << get_factorial( i ) << '\n';
    }
}

程序输出为

0 = 1
1 = 1
2x1 = 2
3x2x1 = 6
4x3x2x1 = 24
5x4x3x2x1 = 120
6x5x4x3x2x1 = 720
7x6x5x4x3x2x1 = 5040
8x7x6x5x4x3x2x1 = 40320
9x8x7x6x5x4x3x2x1 = 362880

或者,该函数也可以看起来像演示程序中的以下方式。

#include <iostream>
#include <string>

std::string get_factorial( unsigned int n )
{
    std::string result = std::to_string( n == 0 ? 0 : 1 );
    unsigned long long factorial = 1;

    for ( unsigned int i = 1; i++ < n; )
    {
        result += 'x' + std::to_string(i);
        factorial *= i;
    }

    return result  + " = " + std::to_string( factorial );
}

int main()
{
    for (unsigned int i = 0; i < 10; i++)
    {
        std::cout << get_factorial( i ) << '\n';
    }
}

程序输出为

0 = 1
1 = 1
1x2 = 2
1x2x3 = 6
1x2x3x4 = 24
1x2x3x4x5 = 120
1x2x3x4x5x6 = 720
1x2x3x4x5x6x7 = 5040
1x2x3x4x5x6x7x8 = 40320
1x2x3x4x5x6x7x8x9 = 362880

注意unsigned long long int类型可以存储n等于20的阶乘的最大值。

bvjxkvbb

bvjxkvbb2#

在C23中,您可以使用C视图和范围轻松地完成此操作:

#include <algorithm>
#include <iostream>
#include <ranges>
#include <string>

int calc_factorial(int num) {
   int sum = 1;
   while(num > 0) {
       sum = sum * num;
       num--;
   }
   return sum;
}

void print_factorial(const int num) {
    if (num == 0) {
        std::cout << '0';
    } else {
        std::ranges::copy(
            std::views::iota(1) |
            std::views::take(num) |
            std::views::transform([](auto v){ return std::to_string(v); }) |
            std::views::join_with('x'),
            std::ostream_iterator<char>(std::cout));
    }

    std::cout << " = " << calc_factorial(num) << '\n';
}

int main() {
    for(const int num: std::views::iota(0, 12)) {
        print_factorial(num);
    }
}
0 = 1
1 = 1
1x2 = 2
1x2x3 = 6
1x2x3x4 = 24
1x2x3x4x5 = 120
1x2x3x4x5x6 = 720
1x2x3x4x5x6x7 = 5040
1x2x3x4x5x6x7x8 = 40320
1x2x3x4x5x6x7x8x9 = 362880
1x2x3x4x5x6x7x8x9x10 = 3628800
1x2x3x4x5x6x7x8x9x10x11 = 39916800

std::views::iota(begin, end)生成从包含begin到排除end的值。
使用std::views::iota(1)可以创建一个从1开始的值的无穷序列。(注意视图是延迟求值的!)std::views::take(num)使num在到达num后停止生成。您可以使用std::views::iota(1, num + 1)完成相同的操作。
std::views::transform通过lambda调用std::to_stringint值转换为std::string。或者,您可以直接向函数传递引用或指针,但由于std::to_string有多个重载,因此必须通过static_cast选择int重载。或者,您可以直接向函数传递引用或指针。但是因为std::to_string有多个重载,int重载必须通过static_cast来选择。这比lambda的可读性差,但是至少更有效,因为lambda在C20之前总是创建一个空对象。从C23开始,你可以通过将函数操作符定义为静态函数来禁止在没有捕获的情况下为lambda创建对象。2这和强制转换一样有效。

std::views::transform(static_cast<std::string(&)(int)>(std::to_string))
std::views::transform(static_cast<std::string(*)(int)>(std::to_string))
std::views::transform([](int v) static { return std::to_string(v); })

(Note:默认情况下,使无捕获的lambdas static会破坏向后兼容性。)
std::views::join_withstd::string展开为char序列,并在这些序列之间添加'x'。结果是char的长序列,其中包含要创建的字符序列。
std::ranges::copy将此char序列复制到std::cout
join_with视图是C23,其他视图是C20。
如果你坚持使用比C++23更老的标准,或者你只是不想使用视图和范围的方法,你可以实现print函数如下:

#include <iostream>

int calc_factorial(int num) {
   int sum = 1;
   while(num > 0) {
       sum = sum * num;
       num--;
   }
   return sum;
}

void print_factorial(const int num) {
    if (num < 2) {
        std::cout << num;
    } else {
        std::cout << 1;
        for(int i = 2; i <= num; ++i) {
            std::cout << 'x' << i;
        }
    }

    std::cout << " = " << calc_factorial(num) << '\n';
}

int main() {
    for(int i = 0; i < 12; ++i) {
        print_factorial(i);
    }
}

实际上,这种实现可能更好,因为它不太复杂,而且效率更高(另一种方法使用std::to_string,可能比较慢)。
然而,这个问题非常适合于演示视图和范围的使用,因此详细描述了这种方法。- )

wj8zmpe1

wj8zmpe13#

你不需要std::to_string(或者std::stringstream),你要用的数字就这么多,所以,定义

string digits = "0123456789";

并使用数字[n/10]或数字[n%10]挑选相关字符。
你可能只能做阶乘(20)。

相关问题