27 agosto, 2019

Un po' di matematica


Qualche funzione di quelle cose che s'incontrano in matematica, roba semplice, da scuola dell'obbligo. E sì, lo so, è solo un gioco.

Prima di cominciare: ci sono dei vincoli, uso Python e Bash invece di mezzi più pratici (e potenti); per esempio c'è Maxima ma anche le REPL dei linguaggi usuali (e meno usuali, ecco Racket:

$ rkt
Welcome to Racket v6.11.
> (require math/number-theory)
> (factorize 823543)
'((7 7))
> (factorize 9657787)
'((9657787 1))
> (factorize 3628800)
'((2 8) (3 4) (5 2) (7 1))
> ^D

$


o Pyhton

$ py3
>>> import math
>>> math.factorial(10)
3628800
>>>
$

Allora parto. Tutti sanno cos'è il fattoriale di un numero ma per quelli come me che la memoria... ecco la Wiki.

In Python è predefinita, nel modulo math per cui lo script è semplicissimo:

#!/usr/bin/python3

from math import factorial
from sys import argv

n = int(argv[1])
print(factorial(n))

ed ecco:

$ py3 fact.py 20
2432902008176640000
$ py3 fact.py 100
933262154439441526816992388562667004907159682643816214685929
638952175999932299156089414639761565182862536979208272237582
51185210916864000000000000000000000000
$

Con Bash invece bisogna farla, ma è altrettanto semplice:

#!/bin/bash

N=$1

F=1 #fattoriale
for (( N ; N > 1 ; N-- )); do
    F=$(( F * N ))
done

echo $F


funziona per numeri non troppo grandi:

$ bash fact.sh 10
3628800

$ bash fact.sh 20
2432902008176640000

$
bash fact.sh 100
0


OOPS! errore qui. Il numero limite è 20, dove 20! ~= 2.433e+18:

$ bash fact.sh 20
2432902008176640000

$
bash fact.sh 21
-4249290049419214848

$


Una soluzione migliore si avrebbe ricorrendo a bc.

Scomposizione del numero in fattori primi, qui la Wiki è solo un abbozzo in italiano, per saperne di più c'è la versione inglese.

Con Linux c'è factor:

$ factor 823543
823543: 7 7 7 7 7 7 7

$
factor 9657787
9657787: 9657787

$
factor 3628800
3628800: 2 2 2 2 2 2 2 2 3 3 3 3 5 5 7

$

In Python manca (o non l'abbiamo trovata) ma si può fare, anzi basta chiedere a Stack Overflow, versione personalizzata:

#!/usr/bin/python3

from sys import argv
from math import sqrt

def factorize(n):
   if n == 0: return [[0, 1]]
   elif n == 1: return [[1, 1]]
   else:
      factors = []
      divisor = 2
      lim = int(sqrt(n))
      while divisor <= lim:
         power = 0
         while (n % divisor) == 0:
            n //= divisor
            power += 1
         if power > 0:
            factors.append([divisor, power])
         divisor += 1
      if len(factors) == 0:
        factors = [n, 1]

      return factors

n = int(argv[1])
print(factorize(n))


ed ecco:

$ py3 comp.py 823543
[[7, 7]]

$
py3 comp.py 9657787
[9657787, 1]

$
py3 comp.py 3628800
[[2, 8], [3, 4], [5, 2], [7, 1]]

$


La versione Bash si potrebbe fare ma per adesso ci accontentiamo di quella predefinita, funziona con numeri grandi, sarebbero solo da raccogliere:

$ rkt
Welcome to Racket v6.11.
> (require math/number-theory)
> (define n (expt 2 64))
> n
18446744073709551616
> (factorize n)
'((2 64))
> ^D

$
factor 18446744073709551616
18446744073709551616: 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

$


e anche

$ rkt
Welcome to Racket v6.11.
> (require math/number-theory)
> (define n (* 2 3 5 7 11 13 17 19 23 29 31 37 41 43
               47 53 59 61 67 71 73 79 83 89 97))

> n
2305567963945518424753102147331756070
> (factorize n)
'((2 1) (3 1) (5 1) (7 1) (11 1) (13 1) (17 1) (19 1) (23 1)
  (29 1) (31 1) (37 1) (41 1) (43 1) (47 1) (53 1) (59 1)
  (61 1) (67 1) (71 1) (73 1) (79 1) (83 1) (89 1) (97 1))
> ^D

$ factor 2305567963945518424753102147331756070
2305567963945518424753102147331756070: 2 3 5 7 11 13 17 19 23
29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
 
$

Il massimo comun divisore MCD, conosciuto anche come gcd, è predefinito in Python:

#!/usr/bin/python3

from math import gcd
from sys import argv

if len(argv) != 3:
    print('errore, mancano i due numeri')
    exit(2)

try:
    print(gcd(int(argv[1]), int(argv[2])))
except:
    print('errore di input')
    exit(1)


$ py3 gcd.py 80 15
5
 
$ py3 gcd.py 120 18
6

$ py3 gcd.py 120 24
24

$ py3 gcd.py 226553150 1023473145
5

$

La versione Bash

#!/bin/bash

a=$1
b=$2
while [ $b -ne 0 ]; do
  remainder=$(( $a % $b ))
  a=$b
  b=$remainder
done

echo $a


$ bash gcd.sh 80 15
5
 
$ bash gcd.sh 120 18
6

$ bash gcd.sh 120 24
24

$ bash gcd.sh 226553150 1023473145
5

$

Infine il minimo comune multiplo, la Wiki qui e qui.

La versione Python è immediata:

#!/usr/bin/python3

from sys import argv
from math import gcd

def lcm(a, b):
    return a * b // gcd(a, b)

a = int(argv[1])
b = int(argv[2])

print(lcm(a, b))


$ py3 lcm.py 80 15
240
$ py3 lcm.py 21 6
42
$ py3 lcm.py 7 823543
823543

Per Bash si può usare gcd.sh:

#!/bin/bash

GCD=$(. ./gcd.sh $1 $2)
echo $(( $1 * $2 / $GCD ))


$ bash lcm.sh 80 15
240
$ bash lcm.sh 21 6
42
$ bash lcm.sh 7 823543
823543
$

OK, per adesso basta così, Il post è stato fatto a 4 mani durante le ferie/vacanze; ed è stata dura, sono intervenute anche le complicazioni dovute ai fusi orari in aggiunta alle solite.
🔴

Nessun commento:

Posta un commento