Berechnen Sie die Superwurzel einer Zahl

10

In der Mathematik ist die Tetration der nächste Hyperoperator nach der Exponentiation und wird als iterierte Exponentiation definiert.

Zusatz ( a gelungen n - mal)

Multiplikation ( a addiert zu sich selbst, n - mal)

Potenzierung ( a multipliziert mit sich selbst, n- mal)

Tetration ( eine von sich selbst potenzierte , n- mal)

Die inversen Tetrationsbeziehungen werden als Superwurzel und Superlogarithmus bezeichnet. Ihre Aufgabe ist es, ein Programm zu schreiben, das bei A und B die Superwurzel B nd -order von A druckt .

Zum Beispiel:

  • Wenn A = 65,536und B = 4, wird gedruckt2
  • Wenn A = 7,625,597,484,987und B = 3, wird gedruckt3

A und B sind positive ganze Zahlen und das Ergebnis muss eine Gleitkommazahl mit einer Genauigkeit von 5 Stellen nach dem Dezimalpunkt sein. Das Ergebnis gehört zur realen Domäne.

Seien Sie vorsichtig, Superwurzeln können viele Lösungen haben.

Andrea Ciceri
quelle
1
Gibt es minimale / maximale Grenzen für die Eingabenummern? Sollte eine gültige Antwort Gleitkomma-Antworten unterstützen oder nur eine Ganzzahl?
Josh
3
Sollte das Programm bei mehreren Lösungen alle oder nur eine finden?
Johannes H.
5
Was sind Ihre Gewinnkriterien?
Mhmd
2
Können Sie ein einfaches Beispiel für eine Superwurzel geben, die mehr als eine Lösung für ein gegebenes A und B ≥ 1 hat?
Tobia
1
Können Sie die mathematische Darstellung einer Superwurzel geben? Ich fürchte, ich verstehe immer noch nicht, wie es definiert ist.

Antworten:

6

C - Aus Gründen der Klarheit wurde nicht versucht, den Code zusammenzudrücken

Berücksichtigung der Eingabe:

A: A ∈ ℝ, A ≥ 1.0
B: B ∈ ℕ, B ≥ 1

Dann sollte es normalerweise nur eine Lösung in ℝ geben, was das Problem erheblich vereinfacht.

Code ist:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define TOLERANCE    1.0e-09

double tetrate(double, int);

int main(int argc, char **argv)
{
    double target, max, min, mid, working;
    int levels;

    if (argc == 3)
    {
        target = atof(argv[1]); // A
        levels = atoi(argv[2]); // B

        // Shortcut if B == 1
        if (levels == 1)
        {
            printf("%f\n", target);
            return 0;
        }

        // Get a first approximation
        max = 2.0;
        while (tetrate(max, levels) < target)
            max *= 2.0;

        min = max / 2.0;

        // printf("Answer is between %g and %g\n", min, max);

        // Use bisection to get a closer approximation
        do
        {
            mid = (min + max) / 2.0;
            working = tetrate(mid, levels);
            if (working > target)
                max = mid;
            else if (working < target)
                min = mid;
            else
                break;
        }
        while (max - min > TOLERANCE);

        // printf("%g: %f = %f tetrate %d\n", target, tetrate(mid, levels), mid, levels);
        printf("%f\n", mid);
    }

    return 0;
}

double tetrate(double d, int i)
{
    double result = d;

    // If the result is already infinite, don't tetrate any more
    while (--i && isfinite(result))
        result = pow(d, result);

    return result;
}

Kompilieren:

gcc -o tet_root tet_root.c -lm

Laufen:

./tet_root A B

Z.B:

4 2

$ ./tet_root 65536 4
2.000000

3 3

$ ./tet_root 7625597484987 3
3.000000

3 π

$ ./tet_root 1.340164183e18 3
3.141593

n (2 ½ ) ➙ 2 als n ➙ ∞? (bekannte Grenze)

$ ./tet_root 2 10
1.416190

$ ./tet_root 2 100
1.414214

$ ./tet_root 2 1000
1.414214

Ja!

n (e 1 / e ) ➙ ∞ als n ➙ ∞? (Obergrenzen)

$ ./tet_root 9.999999999e199 100
1.445700

$ ./tet_root 9.999999999e199 1000
1.444678

$ ./tet_root 9.999999999e199 10000
1.444668

$ ./tet_root 9.999999999e199 100000
1.444668

Cool! (e 1 / e ≅ 1.44466786101 ...)


quelle
Sie wissen tatsächlich viel über Mathematik, die ich sagen kann :) (Diese Antwort) ∈ (wirklich beeindruckendes Zeug)
Albert Renshaw
@ AlbertRenshaw Dies ist nur eine Implementierung der Halbierung. Gar nicht so schwer.
Einfach schöne Kunst
5

Python, 87 Zeichen

E=lambda x,n:x**E(x,n-1)if n else 1
def S(A,B):
 x=1.
 while E(x,B)<A:x+=1e-5
 return x

Eine einfache lineare Suche nach der Antwort.

Off-Topic, aber was ist mit dem Python- **Operator * # $ (@!) ?

>>> 1e200*1e200
inf
>>> 1e200**2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Numerical result out of range')
Keith Randall
quelle
Einen Fehlerbericht wert?
Josh
Stört die Assoziativität? Vielleicht vergleichen Sie (1e200)**2mit 1e(200**2)?
Danmcardle
2
@Josh: Ich habe einen Fehler gemeldet: bugs.python.org/issue20543 Grundsätzlich funktioniert es wie beabsichtigt - sie sind nicht viel für IEEE Float. Wenn sie irgendetwas reparieren würden, wäre es OverflowErrorim ersten Fall eine zu generieren .
Keith Randall
3

Mathematica, 35 40

n /. Solve[Nest[#^(1/n) &, a, b] == n]~N~5

Erzeugt eine Liste aller Lösungen mit 5-stelliger Genauigkeit.

n /. Last@Solve[Nest[#^(1/n) &, a, b] == n]~N~5

5 weitere Zeichen, um nur die echte Lösung zu erhalten, die die aktualisierten Regeln verlangen.

Shrx
quelle
2

Julia

julia> t(a,b)=(c=a;for j=1:b-1;c=a^c;end;c)
julia> s(c,b)=(i=1;while t(i,b)!=c;i+=1;end;i)
julia> s(65536,4)
2
julia> s(7625597484987,3)     
3

Ignorierte Gleitkommaanweisung, da die Frage nur das Verhalten für Ganzzahlen definiert.

gggg
quelle
2

Wann wurde dies ein Code Golf? Ich dachte, es wäre eine Code-Herausforderung, den besten Algorithmus zu finden!


APL, 33 Zeichen

{r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6}

Dies ist eine einfache lineare Suche, die von C = 1 + 10 -6 ausgeht und um 10 -6 erhöht wird, bis
    log C log C log C ⋯ A ≤ 1,
wobei die log C- Funktion B-mal rekursiv angewendet wird.

Beispiele

      4 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 65536
2.0000009999177335
      3 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 7625597484987
3.0000000000575113

Dieser Code ist sehr langsam, aber für kleine Basen wie 2 oder 3 ist er in wenigen Sekunden fertig. Siehe unten für eine bessere Sache.


APL, logarithmische Komplexität

Tatsächlich lineare Komplexität in der Stammreihenfolge, logarithmisch in Bezug auf Ergebnisgröße und Genauigkeit:

    Zeit = O (B × log (C) + B × log (D))

Dabei ist B die Grundreihenfolge, C die angeforderte Tetrationsbasis und D die Anzahl der angeforderten Genauigkeitsziffern. Diese Komplexität ist mein intuitives Verständnis, ich habe keinen formalen Beweis erbracht.

Dieser Algorithmus erfordert keine großen Ganzzahlen, sondern verwendet die Protokollfunktion nur für reguläre Gleitkommazahlen. Daher ist er für sehr große Zahlen bis zur Grenze der Gleitkommaimplementierung (entweder doppelte Genauigkeit oder beliebig große FP-Zahlen auf der.) Sehr effizient APL-Implementierungen, die sie anbieten.)

Die Genauigkeit des Ergebnisses kann durch Einstellen ⎕CT(Vergleichstoleranz) auf den gewünschten akzeptablen Fehler gesteuert werden (auf meinem System ist der Standardwert 1e ¯ 14, ungefähr 14 Dezimalstellen).

sroot←{              ⍝ Compute the ⍺-th order super-root of ⍵:
  n←⍺ ⋄ r←⍵          ⍝ n is the order, r is the result of the tetration.
  u←{                ⍝ Compute u, the upper bound, a base ≥ the expected result:
    1≥⍵⍟⍣n⊢r:⍵       ⍝   apply ⍵⍟ (log base ⍵) n times; if ≤1 then upper bound found
    ∇2×⍵             ⍝   otherwise double the base and recurse
  }2                 ⍝ start the search with ⍵=2 as a first guess.
  (u÷2){             ⍝ Perform a binary search (bisection) to refine the base:
    b←(⍺+⍵)÷2        ⍝   b is the middle point between ⍺ and ⍵
    t←b⍟⍣n⊢r         ⍝   t is the result of applying b⍟ n times, starting with r;
    t=1:b            ⍝   if t=1 (under ⎕CT), then b is the super-root wanted;
    t<1:⍺∇b          ⍝   if t<1, recurse between ⍺ and b
    b∇⍵              ⍝   otherwise (t>1) returse between b and ⍵
  }u                 ⍝ begin the search between u as found earlier and its half.
}

Ich bin nicht sicher, ob 1≥⍵⍟⍣noben ein Domänenfehler fehlschlagen könnte (da das Protokoll eines negativen Arguments entweder sofort fehlschlagen oder ein komplexes Ergebnis liefern könnte, das nicht in der Domäne von liegt ), aber ich konnte es nicht finden ein Fall, der fehlschlägt.

Beispiele

      4 sroot 65536
1.9999999999999964
      4 sroot 65537
2.000000185530773
      3 sroot 7625597484987
3
      3 sroot 7625597400000
2.999999999843567
      3 sroot 7625597500000
3.000000000027626

'3' wird als exakter Wert ausgegeben, da es sich zufällig um einen der Werte handelt, die direkt von der binären Suche getroffen werden (beginnend mit 2, verdoppelt auf 4, halbiert auf 3). In dem allgemeinen Fall, in dem dies nicht der Fall ist, nähert sich das Ergebnis dem Wurzelwert mit einem ⎕CT-Fehler an (genauer gesagt, der logarithmische Test jeder Kandidatenbasis wird mit ⎕CT-Toleranz durchgeführt.)

Tobia
quelle
1

Ruby, 79 Bytes

->a,b{x=y=1.0;z=a;eval"y=(x+z)/2;x,z=a<eval('y**'*~-b+?y)?[x,y]:[y,z];"*99;p y}

Dies ist das gleiche wie das folgende Programm, jedoch weniger genau, da nur 99 Schleifen ausgeführt werden.

Ruby, 87 Bytes

->a,b{x=y=1.0;z=a;(y=(x+z)/2;x,z=a<eval("y**"*~-b+?y)?[x,y]:[y,z])while y!=(x+z)/2;p y}

Probieren Sie es online aus

Dies ist einfach eine Halbierung. Ungolfed:

-> a, b {
    # y^^b by evaluating the string "y ** y ** ..."
    tetration =-> y {eval "y ** " * (b-1) + ?y}

    lower = middle = 1.0
    upper = a

    while middle != (lower + upper) / 2 do
        middle = (lower + upper) / 2

        if tetration[middle] > a
            upper = middle
        else
            lower = middle
        end
    end

    print middle
}
Einfach schöne Kunst
quelle
0

k [52 Zeichen]

{{{((%x)*(z*x-1)+y%z xexp x-1)}[x;y]/[2]}[y]/[y<;x]}

Eine modifizierte Version meiner eigenen Beitrag n - te Wurzel

Beispiel:

{{{((%x)*(z*x-1)+y%z xexp x-1)}[x;y]/[2]}[y]/[y<;x]}[7625597484987;3]
3f 

{{{((%x)*(z*x-1)+y%z xexp x-1)}[x;y]/[2]}[y]/[y<;x]}[65536;4]
2f
Nyi
quelle
0

Haskell

Einfache lineare Suche, gibt zuerst zurück, kleinste gefundene Übereinstimmung.

{-
    The value of a is the result of exponentiating b some number of times.
    This function computes that number.
-}
superRoot a b = head [x | x<-[2..a], tetrate x b == a]

{-
    compute b^b^...^b repeated n times
-}
tetrate b 1 = b
tetrate b n = b^(tetrate b (n-1))

Beispiel

*Main> superRoot 65536 4
2
*Main> superRoot 7625597484987 3
3
Danmcardle
quelle
0

Mathematica, 41 Bytes ohne Optimierung

Mathematica wurde im Grunde erfunden, um solche Probleme zu lösen. Eine einfache Lösung besteht darin, das Problem als verschachtelte Potenzreihe zu konstruieren und an die integrierte ReduceFunktion zu übergeben, die nach analytischen Lösungen für Gleichungen sucht. Infolgedessen ist das Folgende nicht nur ungewöhnlich prägnanter Code, sondern auch keine rohe Gewalt.

Reduce[Nest[Power[#, 1/x] &, a, b] == x, x, Reals]

Sie können die Einschränkung aufheben, um nur Lösungen mit reellen Zahlen bereitzustellen, wenn Sie geduldig sind und sechs Bytes sparen möchten. Sie können einige der verschachtelten Funktionen auch in Kurzform ausdrücken, um einige weitere Bytes zu sparen. Wie gegeben, kehrt es so zurück

Geben Sie hier die Bildbeschreibung ein

Michael Stern
quelle
0

05AB1E , 16 Bytes

1[ÐU²FXm}¹@#5(°+

Port der Python-Antwort von @KeithRandall .

Probieren Sie es online aus.

Erläuterung:

1                 # Push a 1
 [                # Start an infinite loop:
  Ð               #  Triplicate the top value on the stack
   U              #  Pop and store one in variable `X`
    ²F            #  Inner loop the second input amount of times:
      Xm          #   And take the top value to the power `X`
        }         #  After the inner loop:
         ¹@       #  If the resulting value is larger than or equal to the first input:
           #      #   Stop the infinite loop
                  #   (after which the top of the stack is output implicitly as result)
            5(°+  #  If not: increase the top value by 10^-5

ÐU²FXm}könnte auch D²>и.»mfür die gleiche Byteanzahl sein:

  D               #   Duplicate the top value on the stack
   ²>             #   Push the second input + 1
     и            #   Repeat the top value that many times as list
                #   Reduce it by:
        m         #    Taking the power
Kevin Cruijssen
quelle