antes de Cristo

antes de Cristo

Estoy intentando escribir un script (script1.sh) que proporcione la suma de cada dígito del primer número, elevado a la potencia del segundo número. Entonces

./script1.sh 12345 2

debería salir55

(porque 1+4+9+16+25=55)

o./script1.sh 3706907995955475988644381 25

debería dar salida 3706907995955475988644381.

Escribí un guión pero en algunos casos obtengo un resultado negativo y no veo cómo puede suceder eso.

Por ejemplo

./script1.sh 3706907995955475988644380 25

salidas

-2119144605827694052

Mi guión:

#!/bin/bash
sum=0

value=$1

arr=()
for ((i = 0; i < ${#value}; i++)); do
    arr+=(${value:$i:1})
done

for x in "${arr[@]}"; do
    sum=$(($sum+(x**$2)))
done
echo $sum

Respuesta1

La aritmética de shell bashutiliza el tipo de entero más amplio admitido por su compilador de C. En la mayoría de los sistemas/compiladores C modernos, son enteros de 64 bits, por lo que "solo" cubre el rango -9223372036854775808 a 9223372036854775807, y ajusta los números fuera de ese. Para hacer esto necesitarás usar otra herramienta, como bc:

#!/bin/bash

num1=$1
num2=$2
sum=0

for (( i=0; i<${#num1}; i++ )); do
    n=${num1:$i:1}
    sum=$( bc <<<"$sum + $(bc <<<"${n}^$num2")" )
done

echo "$sum"

Respuesta2

Con cortoawkguion:

sum_powered.awkguion:

#!/bin/awk -f
BEGIN{
    split(ARGV[1], a, "");
    pow = ARGV[2];
    for (i in a) sum += a[i] ** pow;
    print sum;
}

Uso:

$ ./sum_powered.awk 12345 2
55

$ ./sum_powered.awk 3706907995955475988644381 25
3706907995955475217645568

Es posible que necesite agregar permiso de ejecución a un nuevoawkscript antes de ejecutar:

$ chmod +x sum_powered.awk 

Respuesta3

Hacer cálculos que tengan resultados de 25 dígitos ( 3706907995955475988644381) ciertamente está fuera de la capacidad de la mayoría de las implementaciones de shell. De hecho, la aritmética del shell es bastante similar a la aritmética del lenguaje C. En lenguaje C, un entero con signo cambia de signo cuando hay un desbordamiento. El entero más largo común que usaría un sistema de 64 bits tiene un valor limitado a 63 dígitos binarios (el otro bit define el signo del entero), por lo que 63 unos en binario o 0efff ffff ffff ffff en hexadecimal representan el número $( ( (1<<63) - 1 )) o 9223372036854775807 (19 dígitos). El límite negativo es -9223372036854775808.

Un número de 25 dígitos no cabe dentro de un entero de 19 dígitos, por lo que se desborda, comoC enteros con signo se desbordan: cambiando de signo (en la mayoría de las máquinas):

$ echo "$(( 9223372036854775807 + 1 ))"
-9223372036854775808

antes de Cristo

El lenguaje de nivel más bajo que una utilidad (independiente) podría proporcionar para "matemáticas de precisión arbitraria" (números sin un límite de longitud preestablecido) es bc. En bc, no es difícil ejecutar todo el requisito:

x=12345
y=2
scale=0;
s=0;
while (x>0) {
              b=x%10;
          x/=10;
          s+=b^y
        };
s
quit

Escríbalo en un archivo (suponga que se llama digpower.bc) y ejecútelo con esto:

$ bc -q digpower.bc
55

Transformar todo el archivo para que contenga solo una función que se encargue de las variables temporales y devuelva la escala a su valor original:

define d(x,y){
    auto s,b,u; s=scale;
    while (x>0) { b=x%10; x/=10; u+=b^y }
    scale=s; return(u) };

En este caso, llame a bc así:

$ bc -q digpower.bc <<<"d(12345,2)"
55

$ echo "d(3706907995955475988644381,25)" | bc digpower.bc
3706907995955475988644381

pitón

El siguiente lenguaje de nivel superior (omitiendo el ceceo común) que tiene enteros ilimitados (solo mediante la memoria de la computadora) es Python:

$ python3 -c 'x=12345;y=2;s=0;
while (x>0): b=x%10;x//=10;s+=b**y                        
print(s)'
55

La mayoría de los demás lenguajes utilizan algún tipo de flotante, incluido awk. Algunos lenguajes permiten configurar qué tan grandes podrían ser los flotadores (más sobre esto en awk más adelante).

awk

Todos los números del interior awkse almacenan como flotantes. De forma predeterminada, awk usa mantisa de 53 bits. Una mantisa de 53 bits tiene un límite general de 16 dígitos. En algunos flotadores concretos, 17 o incluso 18 dígitos pueden ser exactos.

$ awk -vx=12345 -vy=2 'BEGIN{s=0;while(x>0){b=x%10;x=int(x/10);s+=b^y}; print(s)}'
55

Pero (el mismo código con otros valores):

$ awk -vx=3706907995955475988644381 -vy=25 'BEGIN{s=0;while(x>0){b=x%10;x=int(x/10);s+=b^y}; print(s)}'
2989038141653481752100864

Lo cual obviamente es incorrecto porque la representación interna como flotante es bastante incorrecta después de los 16 dígitos. Sólo para mostrarlo:

$ awk -vx=3706907995955475988644381 'BEGIN{print(x);print(x+0)}'
3706907995955475988644381
3706907995955475754516480

Esos errores conducen a errores mayores.

Existe la alternativa con GNU awk de aumentar el número de bits de la mantisa flotante si awk tiene bignum compilado (la salida de awk --version contiene "GNU MPFR"):

$ awk -M -v PREC=100 -vx=3706907995955475988644381 -vy=25 'BEGIN{s=0;while(x>0){b=x%10;x=int(x/10);s+=b**y}; print(s)}'
3706907995955475988644381

Un dígito decimal de 25 requiere aproximadamente 25*log(2)/log(10)dígitos binarios o una mantisa de 83 bits (la respuesta exacta es bastante más larga de explicar). Usar 100 da suficiente margen.

información relacionada