a.C.

a.C.

Estou tentando escrever um script (script1.sh) que forneça a soma de cada dígito do primeiro número, elevado à potência do segundo número. Então

./script1.sh 12345 2

deve produzir55

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

ou./script1.sh 3706907995955475988644381 25

deve produzir 3706907995955475988644381.

Escrevi um script, mas em alguns casos recebo um resultado negativo e não vejo como isso pode acontecer.

Por exemplo

./script1.sh 3706907995955475988644380 25

saídas

-2119144605827694052

Meu roteiro:

#!/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

Responder1

A aritmética do shell bashusa o tipo inteiro mais amplo suportado pelo seu compilador C. Na maioria dos sistemas modernos/compiladores C, são números inteiros de 64 bits, portanto, "apenas" cobrindo o intervalo -9223372036854775808 a 9223372036854775807 e agrupando números fora disso. Para fazer isso você precisará usar outra ferramenta, 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"

Responder2

Com curtoawkroteiro:

sum_powered.awkroteiro:

#!/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

Talvez seja necessário adicionar permissão de execução a um novoestranhoscript antes de executar:

$ chmod +x sum_powered.awk 

Responder3

Fazer contas com resultados de 25 dígitos ( 3706907995955475988644381) certamente está fora da capacidade da maioria das implementações de shell. Na verdade, a aritmética do shell é bastante semelhante à aritmética da linguagem C. Na linguagem C, um número inteiro assinado muda de sinal quando há estouro. O inteiro de sistema mais longo comum para um sistema de 64 bits usaria tem um valor limitado a 63 dígitos binários (o outro bit define o sinal do inteiro), então, 63 1's em binário ou 0efff ffff ffff ffff em hexadecimal representa o número $( ( (1<<63) - 1 )) ou 9223372036854775807 (19 dígitos). O limite negativo é -9223372036854775808.

Um número de 25 dígitos não cabe em um número inteiro de 19 dígitos, então ele transborda, comoEstouro de inteiros assinados em C: alterando o sinal (na maioria das máquinas):

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

a.C.

A linguagem de nível mais baixo que um utilitário (autônomo) poderia fornecer para "matemática de precisão arbitrária" (números sem limite de comprimento predefinido) é bc. No bc, não é difícil executar todo o requisito:

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

Escreva isso em um arquivo (suponha que seja chamado digpower.bc) e execute com isto:

$ bc -q digpower.bc
55

Transformando todo o arquivo para conter apenas uma função que cuida das variáveis ​​temporais e retornando a escala ao seu 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) };

Neste caso, chame bc assim:

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

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

Pitão

A próxima linguagem de nível superior (ignorando Common lisp) que possui números inteiros ilimitados (apenas pela memória do computador) é Python:

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

A maioria das outras linguagens usa alguma forma de floats, incluindo awk. Algumas linguagens permitem definir o tamanho dos carros alegóricos (mais sobre isso no awk posteriormente).

estranho

Todos os números internos awksão armazenados como números flutuantes. Por padrão, o awk usa mantissa de 53 bits. Uma mantissa de 53 bits tem um limite geral de 16 dígitos. Em alguns carros alegóricos específicos, 17 ou até 18 dígitos podem ser exatos.

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

Mas (o mesmo código com outros 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

O que é obviamente errado porque a representação interna como float fica bastante errada após os 16 dígitos. Só para mostrar:

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

Esses erros levam a erros maiores.

Existe a alternativa com GNU awk de aumentar o número de bits da mantissa flutuante se o awk tiver bignum compilado (a saída de awk --version contém "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

Um dígito decimal de 25 requer cerca 25*log(2)/log(10)de dígitos binários ou uma mantissa de 83 bits (a resposta exata é bem mais longa para explicar). Usar 100 dá margem suficiente.

informação relacionada