v. Chr.

v. Chr.

Ich versuche, ein Skript (script1.sh) zu schreiben, das die Summe aller Ziffern der ersten Zahl hoch der zweiten Zahl angibt. Also

./script1.sh 12345 2

sollte ausgeben55

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

oder./script1.sh 3706907995955475988644381 25

sollte ausgeben 3706907995955475988644381.

Ich habe ein Skript geschrieben, aber in einigen Fällen erhalte ich eine negative Ausgabe und ich verstehe nicht, wie das passieren kann.

Zum Beispiel

./script1.sh 3706907995955475988644380 25

Ausgänge

-2119144605827694052

Mein Skript:

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

Antwort1

Die Shell-Arithmetik bashverwendet den breitesten Integer-Typ, der von Ihrem C-Compiler unterstützt wird. Auf den meisten modernen Systemen/C-Compilern sind das 64-Bit-Integer, also „nur“ der Bereich -9223372036854775808 bis 9223372036854775807, und für Zahlen außerhalb dieses Bereichs wird ein Wrapper ausgeführt. Dazu müssen Sie ein anderes Tool wie bc verwenden:

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

Antwort2

Mit kurzenawkSkript:

sum_powered.awkSkript:

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

Verwendung:

$ ./sum_powered.awk 12345 2
55

$ ./sum_powered.awk 3706907995955475988644381 25
3706907995955475217645568

Möglicherweise müssen Sie einer neuenawkSkript vor dem Ausführen:

$ chmod +x sum_powered.awk 

Antwort3

Mathematische Berechnungen mit 25-stelligen Ergebnissen ( 3706907995955475988644381) liegen sicherlich außerhalb der Kapazität der meisten Shell-Implementierungen. Tatsächlich ist die Shell-Arithmetik der Arithmetik in der Programmiersprache C sehr ähnlich. In der Programmiersprache C wechselt ein vorzeichenbehafteter Integer das Vorzeichen, wenn ein Überlauf auftritt. Der übliche längste System-Integer, den ein 64-Bit-System verwenden würde, hat einen Wert, der auf 63 Binärziffern begrenzt ist (das andere Bit definiert das Vorzeichen des Integers), also stellen 63 1er im Binärsystem oder 0efff ffff ffff ffff im Hexadezimalsystem die Zahl $(( (1<<63) - 1 )) oder 9223372036854775807 (19 Ziffern) dar. Die negative Grenze ist -9223372036854775808.

Eine 25-stellige Zahl passt nicht in eine 19-stellige Ganzzahl, daher läuft sie über, wieÜberlauf von vorzeichenbehafteten Ganzzahlen in C: durch Änderung des Vorzeichens (auf den meisten Maschinen):

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

v. Chr.

Die Sprache mit der niedrigsten Ebene, die ein (eigenständiges) Dienstprogramm für „Mathematik mit beliebiger Genauigkeit“ (Zahlen ohne voreingestellte Längenbeschränkung) bereitstellen könnte, ist bc. In bc ist es nicht schwierig, die gesamte Anforderung auszuführen:

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

Schreiben Sie das in eine Datei (nehmen Sie an, sie heißt digpower.bc) und führen Sie es wie folgt aus:

$ bc -q digpower.bc
55

Morphen der gesamten Datei, sodass sie nur eine Funktion enthält, die sich um zeitliche Variablen kümmert und die Skalierung auf ihren ursprünglichen Wert zurücksetzt:

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) };

Rufen Sie in diesem Fall bc wie folgt auf:

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

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

Python

Die nächsthöhere Sprache (Common Lisp übersprungen), die über unbegrenzte (nur durch den Computerspeicher) Ganzzahlen verfügt, ist Python:

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

Die meisten anderen Sprachen verwenden irgendeine Form von Floats, einschließlich awk. Einige Sprachen ermöglichen die Einstellung der Float-Größe (weitere Informationen hierzu finden Sie später in awk).

awk

Alle darin enthaltenen Zahlen awkwerden als Gleitkommazahlen gespeichert. Standardmäßig verwendet awk eine 53-Bit-Mantisse. Eine 53-Bit-Mantisse ist im Allgemeinen auf 16 Ziffern begrenzt. Bei einigen Gleitkommazahlen können 17 oder sogar 18 Ziffern genau sein.

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

Aber (derselbe Code mit anderen Werten):

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

Das ist offensichtlich falsch, da die interne Darstellung als Float nach der 16. Ziffer völlig falsch ist. Nur um es zu zeigen:

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

Diese Fehler führen zu größeren Fehlern.

Bei GNU awk besteht alternativ die Möglichkeit, die Anzahl der Bits der Float-Mantisse zu erhöhen, wenn awk über Bignum verfügt (die Ausgabe von awk --version enthält „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

Eine 25-stellige Dezimalstelle erfordert etwa 25*log(2)/log(10)Binärziffern oder eine 83-Bit-Mantisse (die genaue Antwort ist viel länger zu erklären). Die Verwendung von 100 bietet genügend Spielraum.

verwandte Informationen