大家好,我是吴师兄,周末快乐,分享个有趣的编程问题。
这就是一个求阶乘的问题,大家刚刚开始学编程的时候应该都写过这样的程序。
一个求阶乘的问题,还能玩出什么样的花儿来?
我在回答区看到了一个非常有趣的回答,把各种版本的代码都举例了出来,一个比一个还离谱,后面的代码,甚至让怀疑是我学过的代码吗?
分享给大家图个乐,下面是回答正文,答主:小白白。
数学家版本:
(简单利索,深藏功与名)
#include<iostream>#include<cmath>intmain(){std::cout<
语言学家版本:
(语言学家,你懂得,恨不得把所有语法特性都派上用场)
#include<iostream>#include<utility>templateconstexprautofoo(std::index_sequence){return((I+1) * ...); }intmain(){std::cout<< foo(std::make_index_sequence<20>()) <
历史学家版本:
(void main() 有没有嗅到浓厚的历史气息?)
#include<stdio.h>voidmain(void){inti;longlongj;for(i =1, j =1;i <=20; j *= i++);printf("%lld", j); }
敏捷开发上线1.0版本:
(可以说是非常敏捷了)
#include<stdio.h>intmain(){//printf("%d", 1*2*3*4*5*6*7*8*9*10);printf("%lld", (longlong)1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20);}
面向对象专家版本:
(好家伙,一个简单的问题,愣是祭出了接口、继承、虚函数、虚继承、智能指针等一大堆东西出来,这很面向对象)
#include #include #include structIBaseInterface{virtual~IBaseInterface() =0;};inline IBaseInterface::~IBaseInterface() = default;structIDataProvider:virtualpublic IBaseInterface {virtualint first() =0;virtualint last() =0;virtualint next(int v) =0;};structICalculator:virtualpublic IBaseInterface {virtuallong long calc(IDataProvider *) =0;};structIPrinter:virtualpublic IBaseInterface {virtualvoid print(conststd::string &) =0;};structISerializer:virtualpublic IBaseInterface {virtualstd::string serialize(long long value) =0;};structIRunnable:virtualpublic IBaseInterface {virtualvoid run() =0;};class Foo :virtualpublic IRunnable { std::shared_ptr m_dp; std::shared_ptr m_c; std::shared_ptr m_s; std::shared_ptr m_p;public: Foo(std::shared_ptr dp, std::shared_ptr c, std::shared_ptr s, std::shared_ptr p) : m_dp(std::move(dp)), m_c(std::move(c)), m_s(std::move(s)),m_p(std::move(p)) {} void run()override{returnm_p->print(m_s->serialize(m_c->calc(m_dp.get()))); }};class DefaultSerializer :virtualpublic ISerializer {public: std::string serialize(long long value)override{returnstd::to_string(value); }};class StreamPrinter :virtualpublic IPrinter { std::ostream &m_os;public: explicit StreamPrinter (std::ostream &os) : m_os(os) {} void print(conststd::string &s)override{ m_os << s << std::endl; }};class MultiplyAccumulateCalculator :virtualpublic ICalculator {public: long long calc(IDataProvider *dp)override{ int i = dp->first(); long long j = i;doj *= (i = dp->next(i));while(i != dp->last());returnj; }};int main() {structMyDataProvider:virtualpublic IDataProvider { int first()override{return1; } int last()override{return20; } int next(int v)override{returnv+1; } }; Foo foo(std::make_shared(), std::make_shared(), std::make_shared(), std::make_shared(std::cout)); foo.run();}
提前优化的并行版本:
(一看就是精通底层技术的大佬,把CPU拿捏得死死的)
#include<iostream>#include<xmmintrin.h>doublefoo(intx){ __m128 a = {1.0f,2.0f,3.0f,4.0f}; __m128 b = {4.0f,4.0f,4.0f,4.0f}; __m128 c = {1.0f,1.0f,1.0f,1.0f};for(inti =0; i < x /4; ++i, a = _mm_add_ps(a, b)) c = _mm_mul_ps(c, a);for(inti = x %4; i <4; ++i) a[i] =1.0f; c = _mm_mul_ps(c, a);return(double)c[0] * (double)c[1] * (double)c[2] * (double)c[3];}intmain(){std::cout<< foo(20) <
黑魔法版本:
(能看懂这段代码的,都不是普通人!)
#include<iostream>#include<numeric>#include<vector>#include<functional>intmain(){std::vector v(std::atoi(std::end(__DATE__) - (__LINE__) /2) -1);// 2021年,第六行std::iota(v.begin(), v.end(),1);std::cout<()) <
“宏孩儿”元编程版:
(当年看各种C++框架中,排山倒海一样的宏定义,简直令人发指)
#include<boost/preprocessor.hpp>// 由于boost.preprocessor仅提供255以下的整数运算// 所以使用sequence来 (十位个位)(千位百位)(十万位万位) 的方式来表示大整数。// 不进位加法:(77)(66)(55) + (44)(33)(22) = (121)(99)(77)#definePP_ADD_N_N_CARRY_OP(R, DATA, I, ELEM) (BOOST_PP_ADD(BOOST_PP_SEQ_ELEM(I, DATA), ELEM))#definePP_ADD_N_N_CARRY(SEQ_A, SEQ_B) BOOST_PP_SEQ_FOR_EACH_I(PP_ADD_N_N_CARRY_OP, SEQ_A, SEQ_B)// 进位加法:(121)(99)(77) = (21)(0)(78)// 注意SEQ_A的长度要比SEQ_B长#definePP_ADD_N_N_OP(S, STATE, ELEM_CARRY) \ BOOST_PP_SEQ_PUSH_FRONT( \ BOOST_PP_SEQ_REPLACE(STATE, 0, BOOST_PP_MOD(BOOST_PP_ADD(BOOST_PP_SEQ_HEAD(STATE), ELEM_CARRY), 100)), \ BOOST_PP_DIV(BOOST_PP_ADD(BOOST_PP_SEQ_HEAD(STATE), ELEM_CARRY), 100) \ )#definePP_ADD_N_N(SEQ_A, SEQ_B) BOOST_PP_SEQ_REVERSE(BOOST_PP_SEQ_FOLD_LEFT(PP_ADD_N_N_OP, BOOST_PP_SEQ_NIL(0), PP_ADD_N_N_CARRY(SEQ_A, SEQ_B)))// 没什么好说的,X*N = X+X+X+X+X+...+X#definePP_MUL_N_1_EXP_OP(Z, I, DATA) (DATA)#definePP_MUL_N_1_EXP(SEQ_N, N) BOOST_PP_REPEAT(N, PP_MUL_N_1_EXP_OP, SEQ_N)#definePP_MUL_N_1_MYOP(S, STATE, ITEM) PP_ADD_N_N(STATE, ITEM)#definePP_MUL_N_1_FWD(EXP) BOOST_PP_SEQ_FOLD_LEFT(PP_MUL_N_1_MYOP, BOOST_PP_SEQ_HEAD(EXP), BOOST_PP_SEQ_TAIL(EXP))#definePP_MUL_N_1(SEQ_N, N) PP_MUL_N_1_FWD(PP_MUL_N_1_EXP(SEQ_N, N))#defineFACT5 PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1((1), 2), 3), 4), 5)#defineFACT10 PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(FACT5, 6), 7), 8), 9), 10)#defineFACT15 PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(FACT10, 11), 12), 13), 14), 15)#defineFACT20 PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(FACT15, 16), 17), 18), 19), 20)#defineFACT25 PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(PP_MUL_N_1(FACT20, 21), 22), 23), 24), 25)static_assert(false, BOOST_PP_STRINGIZE(FACT10));
真·模板元编程版本
(泛型编程,码不惊人死不休)
#include<iostream>#include<iomanip>#include<type_traits>usingBaseType_t =longlong;constexprBaseType_t lgBase =9;// 注意10000*10000刚刚好小于int的取值范围constexprBaseType_t Base =1000000000;// 注意10000*10000刚刚好小于int的取值范围// 大整数的表示templatestructBigInteger{usingtype = BigInteger;};// 连接templatestructBI_Cat;templatestructBI_Cat, BigInteger> :BigInteger {};// 左移一个单元(即*Base)templatestructBI_SHL;templatestructBI_SHL> :BigInteger {};// 去除开头的0templatestructBI_Remove_Zeros:T {};templatestructBI_Remove_Zeros> :BI_Remove_Zeros> {};// 填充0到N个单元templatestructBI_Fill_Impl;templatestructBI_Fill_Impl> :BigInteger<(I, X)...> {};templatestructBI_Fill_Zeros:BI_Fill_Impl<0,std::make_index_sequence> {};templatestructBI_Resize;templatestructBI_Resize, N> :BI_Cat::type, BigInteger> {};// 返回较大的数值templatestructint_min:std::integral_constant {};// 非进位加法:先把两个数的位数改成一样的然后依次相加templatestructBI_AddNotCarry_Impl;templatestructBI_AddNotCarry_Impl, BigInteger, std::true_type> :BigInteger<(I1 + I2)...> {};templatestructBI_AddNotCarry_Impl, BigInteger, std::false_type> :BI_AddNotCarry_Impl, int_min::value>::type,typenameBI_Resize, int_min::value>::type,std::true_type >{};templatestructBI_AddNotCarry;templatestructBI_AddNotCarry, BigInteger> :BI_AddNotCarry_Impl, BigInteger,std::bool_constant> {};// 判断是否为0templatestructBI_IsZero;templatestructBI_IsZero> :std::bool_constant<((I ==0) && ...)> {};// 自动进位templatestructBI_Carry;templatestructBI_Add:BI_Carry::type> {};template::type>structBI_Carry_Impl;templatestructBI_Carry_Impl :Mod {};templatestructBI_Carry_Impl :BI_Add::type > {};templatestructBI_Carry> :BI_Remove_Zeros, BigInteger<(I / Base)...>>::type> {};// 乘以X并自动进位templatestructBI_MulX;templatestructBI_MulX, X> :BI_Carry> {};// 计算阶乘templatestructBI_Fact:BI_MulX::type, X> {};template<>structBI_Fact<0> :BigInteger<1> {};templatestd::ostream &operator<<(std::ostream &out, BigInteger) {return((out <::type() <
原回答:
https://www.zhihu.com/question/365763395/answer/971009059
不得不服,这位老哥真是人才,把 C++ 玩出这么多花样,不愧是语言学家。当然,现实工作中不会有人这样写代码的,所以大家图个乐就好,不用较真。
你们在第几个版本倒下了?
我反正看到面向对象专家版本就已经忍不住了
···
END
从零开始学算法,无悔做一名程序员!