求2的十万次方各位数之和

题目:求2的十万次方各位数之和Raku、 Perl、Python、Java、Racket、D、C++、Haskell作答分析本题难点在于2的100,000次方,得数是一个大数,足有三万一百零三位,计算器算不出来,直接挂了。

题目:求2的十万次方各位数之和

Raku、 Perl、PythonJava、Racket、D、C++、Haskell作答

分析

本题难点在于2的100,000次方,得数是一个大数,足有三万一百零三位,计算器算不出来,直接挂了。

视频加载中…

感受一下2的十万次方有多大,翻页键往下好几页才装得下,图示是第一屏。

求2的十万次方各位数之和

图示为2的十万次方部分得数

让我们往下看,各种编程语言,如何解答。

Raku代码

raku -e '(2**100_000).split("").sum.say'

Raku代码,一行短代码完事,读起来很顺 — 从左到右依次,2的十万次方(幂操作符**),然后分割为单个数(split),然后累加(sum)。

简洁背后藏着Raku强大的特性:

1) int类型尺寸只受限于内存大小

2) 一切皆为对象,包括整数。split是整数类型的方法。sum是容器的方法。

3)函数式编程风格,让步骤串联,形成流畅的数据流和逻辑,使编写和阅读代码贴合人类思维模式,达到“所想即所写、所写即所得”。

Perl 代码

perl -e 'use bigint; $sum += $_ for (split "", 2**100000); print $sum, "\n"'

感谢bigint,Perl搞定题目没费啥力气,一行代码完事。在终端上直接输入指令回车完成。只不过,Perl代码远不如Raku好懂易写。

Python代码

print(sum(map(int, str(2**100000))))

Python代码对比Raku和Perl代码,算法一模一样。大差别在于可读性。

Raku代码和Perl代码,从左到右读,流畅,接近自然语言。而Python代码呢?第一步,首先必须在大脑中解析括号对,找到嵌套最深的那层2**100000,然后是str,然后往左找到map,最后sum,以此往左逐步求出。初学者想哭。

Java代码

import java.math.BigInteger;

public class SumBigIntDigits {
   public static void main(String[] args) {
       BigInteger n = new BigInteger("2");
       BigInteger total = n.pow(100_000);
       System.out.println(sumDigits(total));
   }

   private static int sumDigits(BigInteger n) {
        int sum = 0;
        BigInteger bi10 = new BigInteger("10");
        BigInteger bi0 = new BigInteger("0");
        while ( n.compareTo(bi0) > 0  ) {
            sum += n.remainder(bi10).intValue();
            n = n.divide(bi10);
        }
        return sum;
   }
}

感谢Java的java.math.BigInteger库,让大数计算不再是梦魇,逃脱了数据溢出。

Java的BigInteger类,有点糙,能干活,写和读不自然。

Racket代码

(define (sum-digits n)
  ;; sum up all the digits of n
    (apply + (digits n)))


(define (digits n)
  ;; output the decimal digits of the given integer
  (define (char->decimal-digit x)
    (- (char->integer x)
       (char->integer #\0)))

  (map char->decimal-digit (string->list (~a n))))

(sum-digits (expt 2 100000))

Racket不仅支持大整数,而且自带expt函数,得精确大数解。优秀!

D代码

import std.stdio;
import std.bigint;


void main() {
    exp(2,100_000).sum_digits
                  .writeln;
}


BigInt exp(int n, uint p) {
    return p == 0       ? BigInt(1)
         : p == 1       ? BigInt(n)
         : p % 2 == 0   ? exp(n, p/2) * exp(n, p/2)
         :                exp(n, 1+p/2) * exp(n, p/2);
}


BigInt sum_digits(BigInt n) {
    return n < BigInt(10) ? n
                          : n % 10 + sum_digits_rec(n / 10);
}

D语言深受C和C++影响,且引入了很多现代化特性,极大改善了表现力和可读性。

D代码简洁,在main函数里从左到右读顺序读出:2的十万次方(exp函数),数位累加(sum_digits),然后输出(writeln)。

简洁背后是强大的特性:

1) 引入了bigint类型

2)函数式编程风格,让方法串接起来,形成流畅的数据流。让代码编写和阅读贴合人类思考过程。

C++代码

#include <iostream>
#include "lib/bignum.h"
using namespace std;

Bignum exp(int n, int p) {
   if ( p == 0 ) return 1;
   if ( p == 1 ) return n;

   return exp(n, p/2) * exp(n, p/2 + (p%2 ? 1 : 0) );
}


int main() {
    Bignum n = exp(2, x);
    cout << n.sumDigits() << endl;
}

这篇文章演示的八种语言,C++是唯一的程序员,没有在语言和标准库层面定义大整数类型,导致引入自造的bignum.h头文件,处理2的十万次方大整数计算。

自造轮子拼不过人家官家货,实际运行效率差强人意。

Haskll代码

digit '0' = 0
digit '1' = 1
digit '2' = 2
digit '3' = 3
digit '4' = 4
digit '5' = 5
digit '6' = 6
digit '7' = 7
digit '8' = 8
digit '9' = 9


sum_digits::Integer -> String
sum_digits = show . sum . map digit . show

main = putStrLn $ sum_digits (2 ^ 100000)

Haskell自带大整数类型,Integer,和幂运算。sum_digits函数求一个数的各位数之和。最后,执行计算,输出计算结果。

Haskell必须显示执行类型转换。这是它与以上所有程序语言不同之处。

运行时间对比

求2的十万次方各位数之和

编译选项:

(Racket) raco exe

(D) dmd -dw -O -m64

(C++) g++ -Wall -std=c++17 -O2

(Haskell) ghc –make -O2

– 结束-

注:本文为原创文章,引用或转载请注明出处。若有任何错误、遗漏、纰漏,烦请指正。

请订阅微信公众号:IT之州

求2的十万次方各位数之和

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/85626.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信