08 luglio, 2019

Calculemus! -- sì, ma forse anche no

Cosa non si trova ontehtoobz! in un tweet oggi questo:


Non so voi ma io  casi come questo mi trovo leibniziano.

Numeri grossi, enormi. Io che sono vecchio subito-subito si accende il *warning* per gli interi [-2^15 : 2^15 - 1]. Poi realizzo che è cosa passata, procedo con la REPL degli usuali (per me) linguaggi preferiti.

E siccome sono pigro invece di mettermi a scrivere codice ricorro a cheat.sh di Igor Chubin, rockz! 💥, devo saperne di più, intanto lo seguo su Twitter.

Racket

$ cht racket factorial
#|
 | traditional recursive factorial and tail-recursive factorial
 | ...https://stackoverflow.com/.../traditional-recursive-factorial-and-
 | tail-recursive-factorial
 |
 | You could use trace (http://docs.racket-
 | lang.org/reference/debugging.html#%28part._.Tracing%29).
 |#

#lang racket

(require racket/trace)

(define factorial
  (lambda (n)
    (if (= n 0)
        1
        (* n (factorial (- n 1))))))
(trace factorial)
(factorial 5)
;; Output:
;; >(factorial 5)
;; > (factorial 4)
;; > >(factorial 3)
;; > > (factorial 2)
;; > > >(factorial 1)
;; > > > (factorial 0)
;; < < < 1
;; < < <1
;; < < 2
;; < <6
;; < 24
;; <120
;; 120

(define factorial-tail
  (lambda (n acc)
    (if (= n 0)
        acc
        (factorial-tail (- n 1)  (* acc n )))))
(trace factorial-tail)
(factorial-tail 5 1)
;; Output:
;; >(factorial-tail 5 1)
;; >(factorial-tail 4 5)
;; >(factorial-tail 3 20)
;; >(factorial-tail 2 60)
;; >(factorial-tail 1 120)
;; >(factorial-tail 0 120)
;; <120
;; 120

; [Greg Hendershott] [so/q/22935169] [cc by-sa 3.0]

$

 
Vado...

$ rkt
Welcome to Racket v6.11.
> (define factorial-tail
    (lambda (n acc)
      (if (= n 0)
          acc
          (factorial-tail (- n 1)  (* acc n )))))

> (define num (* (factorial-tail 20 1) (factorial-tail 7 1)))
> num
12261826121210265600000
> (define den (* (factorial-tail 6 1) (factorial-tail 21 1)))
> den
36785478363630796800000
> (define r (/ num den))
> r
1/3
> (/ 207 621)
1/3
>

OK, avere il tipo razionale è un punto in più per Racket (anzi tutto il Lisp). E per valutare l'ordine di grandezza senza contare le cifre:

> (~r num #:notation 'exponential)
"1.226183e+22"
>

Python

$ cht python factorial
#  Function for Factorial in Python
#
#  Easiest way: math.factorial(x)
#  (https://docs.python.org/library/math.html) (available in 2.6 and
#  above).
#
#  If you want/have to write it yourself, use something like
#  (https://www.artima.com/forums/flat.jsp?forum=181&thread=75931)

def factorial(n):return reduce(lambda x,y:x*y,[1]+range(1,n+1))

#  or something more readable:

def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n-1)

#  As always, Google is your friend ;)
#
#  [schnaader] [so/q/5136447] [cc by-sa 3.0]

$


$
py3
>>> from math import factorial
>>> num = factorial(20) * factorial(7)
>>> num
12261826121210265600000
>>> den = factorial(6) * factorial(21)
>>> den
36785478363630796800000
>>> r = num / den
>>> r
0.3333333333333333
>>> r == (207 / 621)
True
>>>

Node.js --JavaScript

$ cht node factorial
/*
 * What is the fastest factorial function in JavaScript?
 *
 * Lookup table is the obvious way to go, if you're working with natural
 * numbers.
 * To calculate any factorial in real-time, you can speed it with a
 * cache, saving the numbers you've calculated before. Something like:
 */

factorial = (function() {
    var cache = {},
        fn = function(n) {
            if (n === 0) {
                return 1;
            } else if (cache[n]) {
                return cache[n];
            }
            return cache[n] = n * fn(n -1);
        };
    return fn;
})();

/*
 * You can precalculate some values in order to speed it even more.
 *
 * [xPheRe] [so/q/3959211] [cc by-sa 3.0]
 */
$
$ node
> factorial = (function() {
...     var cache = {},
...         fn = function(n) {
.....             if (n === 0) {
.......                 return 1;
.......             } else if (cache[n]) {
.......                 return cache[n];
.......             }
.....             return cache[n] = n * fn(n -1);
.....         };
...     return fn;
... })();

[Function: fn]
> num = factorial(20) * factorial(7)
1.2261826121210266e+22
> den = factorial(6) * factorial(21)
3.6785478363630797e+22
> r = num / den
0.3333333333333333
> r == (207 / 621)
true
>

Però seguire l'istinto a volte non è la cosa migliore, ripensandoci provo...

$ factor 207
207: 3 3 23

$
factor 621
621: 3 3 3 23

ecco c'è un 3 in più nei fattori del denominatore. Se poi provo a sviluppare i fattoriali ottengo:

numeratore
20! * 7! =
    20 * 19 * 18 * 17 * 16 * 15 * 14 * 13 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1
*
    7 * 6 * 5 * 4 * 3 * 2 * 1

denominatore
21! * 6! =
    21 * 20 * 19 * 18 * 17 * 16 * 15 * 14 * 13 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1
*
    6 * 5 * 4 * 3 * 2 * 1

eliminando i termini comuni si ha 7 al numeratore e 21 al denominatore.

Per gli altri casi proposti la semplificazione non è così immediata

$ rkt
Welcome to Racket v6.11.
> (/ 17556 55176)
7/22
> (/ 1500475 4741501)
25/79
>
$ factor 17556
17556: 2 2 3 7 11 19
$ factor 55176
55176: 2 2 2 3 11 11 19
$

$
factor 1500475
1500475: 5 5 47 1277

$
factor 4741501
4741501: 47 79 1277

$


entrano in gioco più fattori ma è la stessa cosa.

OK, le fonti, a me l'ha detto math prof che ha rilanciato (patata) Ichiro.

Chiaro, vero? 沢山のいいねとリツイートありがとうございます!

Resterebbe da chiarire quel ポテト. Ma bisognerebbe immergersi nella cultura jap, vedi il caso affine di 吉本 ばなな.
🔴

Nessun commento:

Posta un commento