
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 bash
utiliza 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 cortoawk
guion:
sum_powered.awk
guion:
#!/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 awk
se 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.