Jump to content

Knuth's power tree

From Rosetta Code
Task
Knuth's power tree
You are encouraged to solve this task according to the task description, using any language you may know.

(Knuth's power tree is used for computing   xn   efficiently.)


Task

Compute and show the list of Knuth's power tree integers necessary for the computation of:

  •   xn   for any real   x   and any non-negative integer   n.


Then, using those integers, calculate and show the exact values of (at least) the integer powers below:

  •   2n     where   n   ranges from   0 ──► 17   (inclusive)
  •   3191
  •   1.181


A  zero  power is often handled separately as a special case.

Optionally, support negative integer powers.


Example

An example of a small power tree for some low integers:

                                                                    1
                                                                     \
                                                                      2
                          ___________________________________________/ \
                         /                                              \
                        3                                                4
                       / \____________________________________            \
                      /                                       \            \
                     5                                         6            8
                    / \____________                           / \            \
                   /               \                         /   \            \
                  7                 10                      9     12           16
                 /                 //\\                     │      │           /\
                /            _____//  \\________            │      │          /  \
              14            /     /    \        \           │      │         /    \
             /│ \         11    13      15       20        18     24        17    32
            / │  \         │    /\      /\        │        /\      │        /\     │
           /  │   \        │   /  \    /  \       │       /  \     │       /  \    │
         19  21    28     22 23   26  25   30    40     27   36    48     33 34   64
         │   /\    /│\     │  │   /\   │   /\    /│\     │   /\    /│\     │  │   /\
         │  /  \  / │ \    │  │  /  \  │  /  \  / │ \    │  /  \  / │ \    │  │  /  \
        38 35 42 29 31 56 44 46 39 52 50 45 60 41 43 80 54 37 72 49 51 96 66 68 65 128

Where, for the power   43,   following the tree "downwards" from   1:

  •   (for   2)   compute square of   X,   store X2
  •   (for   3)   compute   X * X2,   store X3
  •   (for   5)   compute   X3 * X2,   store X5
  •   (for 10)   compute square of   X5,   store X10
  •   (for 20)   compute square of   X10,   store X20
  •   (for 40)   compute square of   X20,   store X40
  •   (for 43)   compute   X40 * X3   (result).

Note that for every even integer (in the power tree),   one just squares the previous value.

For an odd integer, multiply the previous value with an appropriate odd power of   X   (which was previously calculated).   For the last multiplication in the above example, it would be   (43-40),   or   3.

According to Dr. Knuth (see below),   computer tests have shown that this power tree gives optimum results for all of the   n   listed above in the graph.

For   n   ≤ 100,000,   the power tree method:

  •   bests the factor method   88,803   times,
  •   ties   11,191   times,
  •   loses   6   times.


References



Translation of: Python
V p = [1 = 0]
V lvl = [[1]]

F path(n)
   I !n
      R [Int]()
   L n !C :p
      [Int] q
      L(x) :lvl[0]
         L(y) path(x)
            I !(x + y C :p)
               :p[x + y] = x
               q.append(x + y)
      :lvl[0] = q

   R path(:p[n]) [+] [n]

F tree_pow(x, n)
   T Ty = T(x)
   V (r, p) = ([0 = Ty(1), 1 = x], 0)
   L(i) path(n)
      r[i] = r[i - p] * r[p]
      p = i
   R r[n]

F show_pow_i(x, n)
   print("#.: #.\n#.^#. = #.\n".format(n, path(n), x, n, tree_pow(BigInt(x), n)))

F show_pow_f(x, n)
   print("#.: #.\n#.^#. = #.6\n".format(n, path(n), x, n, tree_pow(x, n)))

L(x) 0.<18
   show_pow_i(2, x)
show_pow_i(3, 191)
show_pow_f(1.1, 81)
Output:
0: []
2^0 = 1

1: [1]
2^1 = 2

2: [1, 2]
2^2 = 4

3: [1, 2, 3]
2^3 = 8

4: [1, 2, 4]
2^4 = 16

5: [1, 2, 3, 5]
2^5 = 32

6: [1, 2, 3, 6]
2^6 = 64

7: [1, 2, 3, 5, 7]
2^7 = 128

8: [1, 2, 4, 8]
2^8 = 256

9: [1, 2, 3, 6, 9]
2^9 = 512

10: [1, 2, 3, 5, 10]
2^10 = 1024

11: [1, 2, 3, 5, 10, 11]
2^11 = 2048

12: [1, 2, 3, 6, 12]
2^12 = 4096

13: [1, 2, 3, 5, 10, 13]
2^13 = 8192

14: [1, 2, 3, 5, 7, 14]
2^14 = 16384

15: [1, 2, 3, 5, 10, 15]
2^15 = 32768

16: [1, 2, 4, 8, 16]
2^16 = 65536

17: [1, 2, 4, 8, 16, 17]
2^17 = 131072

191: [1, 2, 3, 5, 7, 14, 19, 38, 57, 95, 190, 191]
3^191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347

81: [1, 2, 3, 5, 10, 20, 40, 41, 81]
1.1^81 = 2253.240236

In this program the power tree is in a generic package which is instantiated for each base value.

with Ada.Containers.Ordered_Maps;
with Ada.Numerics.Big_Numbers.Big_Integers;
with Ada.Text_IO;   use Ada.Text_IO;

procedure Power_Tree is

   Debug_On : constant Boolean := False;

   generic
      type Result_Type is private;
      Base     : Result_Type;
      Identity : Result_Type;
      with function "*" (Left, Right : Result_Type) return Result_Type is <>;
   package Knuth_Power_Tree is
      subtype Exponent is Natural;

      function Power (Exp : Exponent) return Result_Type;
   end Knuth_Power_Tree;

   package body Knuth_Power_Tree is

      package Power_Trees is
        new Ada.Containers.Ordered_Maps (Key_Type     => Exponent,
                                         Element_Type => Result_Type);
      Tree : Power_Trees.Map;

      procedure Debug (Item : String) is
      begin
         if Debug_On then
            Put_Line (Standard_Error, Item);
         end if;
      end Debug;

      function Power (Exp : Exponent) return Result_Type is
         Pow : Result_Type;
      begin
         if Tree.Contains (Exp) then
            return Tree.Element (Exp);
         else
            Debug ("lookup failed of " & Exp'Image);
         end if;

         if Exp mod 2 = 0 then
            Debug ("lookup half " & Exponent'(Exp / 2)'Image);
            Pow := Power (Exp / 2);
            Pow := Pow * Pow;
         else
            Debug ("lookup one less " & Exponent'(Exp - 1)'Image);
            Pow := Power (Exp - 1);
            Pow := Result_Type (Base) * Pow;
         end if;
         Debug ("insert " & Exp'Image);
         Tree.Insert (Key => Exp, New_Item => Pow);
         return Pow;
      end Power;

   begin
      Tree.Insert (Key => 0, New_Item => Identity);
   end Knuth_Power_Tree;


   procedure Part_1
   is
      package Power_2 is new Knuth_Power_Tree (Result_Type => Long_Integer,
                                               Base        => 2,
                                               Identity    => 1);
      R : Long_Integer;
   begin
      Put_Line ("=== Part 1 ===");
      for N in 0 .. 25 loop
         R := Power_2.Power (N);
         Put ("2 **");  Put (N'Image);
         Put (" =");    Put (R'Image);
         New_Line;
      end loop;
   end Part_1;

   procedure Part_2
   is
      use Ada.Numerics.Big_Numbers.Big_Integers;

      package Power_3 is new Knuth_Power_Tree (Result_Type => Big_Integer,
                                               Base        => 3,
                                               Identity    => 1);
      R : Big_Integer;
   begin
      Put_Line ("=== Part 2 ===");
      for E in 190 .. 192 loop
         R := Power_3.Power (E);
         Put ("3 **" & E'Image & " =");  Put (R'Image);  New_Line;
      end loop;
   end Part_2;

   procedure Part_3
   is
      subtype Real is Long_Long_Float;
      package Real_IO is new Ada.Text_IO.Float_IO (Real);
      package Power_1_1 is new Knuth_Power_Tree (Result_Type => Real,
                                                 Base        => 1.1,
                                                 Identity    => 1.0);
      R : Real;
   begin
      Put_Line ("=== Part 3 ===");
      for E in 81 .. 84 loop
         R := Power_1_1.Power (E);
         Put ("1.1 **" & E'Image & " = ");
         Real_IO.Put (R, Exp => 0, Aft => 6);
         New_Line;
      end loop;
   end Part_3;

begin
   Part_1;
   Part_2;
   Part_3;
end Power_Tree;
Output:
=== Part 1 ===
2 ** 0 = 1
2 ** 1 = 2
2 ** 2 = 4
2 ** 3 = 8
2 ** 4 = 16
2 ** 5 = 32
2 ** 6 = 64
2 ** 7 = 128
2 ** 8 = 256
2 ** 9 = 512
2 ** 10 = 1024
2 ** 11 = 2048
2 ** 12 = 4096
2 ** 13 = 8192
2 ** 14 = 16384
2 ** 15 = 32768
2 ** 16 = 65536
2 ** 17 = 131072
2 ** 18 = 262144
2 ** 19 = 524288
2 ** 20 = 1048576
2 ** 21 = 2097152
2 ** 22 = 4194304
2 ** 23 = 8388608
2 ** 24 = 16777216
2 ** 25 = 33554432
=== Part 2 ===
3 ** 190 = 4498196224760364601242719132174628305800834098010033971355568455673974002968757862019419449
3 ** 191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
3 ** 192 = 40483766022843281411184472189571654752207506882090305742200116101065766026718820758174775041
=== Part 3 ===
1.1 ** 81 = 2253.240236
1.1 ** 82 = 2478.564260
1.1 ** 83 = 2726.420686
1.1 ** 84 = 2999.062754

Power tree

We build the tree using tree.lib, adding leaves until the target n is found.

(lib 'tree)

;; displays a chain hit
(define (power-hit target chain)
	(vector-push chain target)
	(printf "L(%d) = %d - chain:%a "
		target (1- (vector-length chain)) chain)
	(vector-pop chain))
	
;; build the power-tree : add 1 level of leaf nodes
;; display all chains which lead to target

(define (add-level node chain  target  nums (new))
(vector-push chain (node-datum node))
	(cond 
	[(node-leaf? node)
	;; add leaves by summing this node to all nodes in chain
	;; do not add leaf if number already known
			 (for [(prev chain)] 
			 		(set! new (+ prev (node-datum node)))
			 		(when (= new target) (power-hit target chain ))
			 		#:continue (vector-search* new nums)
			 		(node-add-leaf node new)
			 		(vector-insert* nums new)
			 		)]
	[else ;; not leaf node -> recurse
	(for [(son  (node-sons node))]
		(add-level son chain target nums )) ])
	(vector-pop chain))
	
;; add levels in tree until target found
;; return (number of nodes . upper-bound for L(target))
(define (power-tree target)
	(define nums (make-vector 1 1)) ;; known nums =  1
	(define T (make-tree 1)) ;; root node has value 1
	(printf "Looking for %d in %a." target T)
	(while #t
	#:break (vector-search* target nums) =>  (tree-count T)
	(add-level T init-chain: (make-vector 0) target  nums)
	))
Output:
(for ((n (in-range 2 18))) (power-tree n))
L(2) = 1 - chain:#( 1 2)
L(3) = 2 - chain:#( 1 2 3)
[ ... ]

(power-tree 17)
Looking for 17 in (🌴 1).
L(17) = 5 - chain:#( 1 2 4 8 16 17)

(power-tree 81)
Looking for 81 in (🌴 1).
L(81) = 8 - chain:#( 1 2 3 5 10 20 40 41 81)
L(81) = 8 - chain:#( 1 2 3 5 10 20 40 80 81)
L(81) = 8 - chain:#( 1 2 3 6 9 18 27 54 81)
L(81) = 8 - chain:#( 1 2 3 6 9 18 36 72 81)
L(81) = 8 - chain:#( 1 2 4 8 16 32 64 65 81)

(power-tree 191)
Looking for 191 in (🌴 1).
L(191) = 11 - chain:#( 1 2 3 5 7 14 19 38 57 95 190 191)
L(191) = 11 - chain:#( 1 2 3 5 7 14 21 42 47 94 188 191)
L(191) = 11 - chain:#( 1 2 3 5 7 14 21 42 63 126 189 191)
L(191) = 11 - chain:#( 1 2 3 5 7 14 28 31 59 118 177 191)
L(191) = 11 - chain:#( 1 2 3 5 7 14 28 31 62 93 186 191)
L(191) = 11 - chain:#( 1 2 3 5 10 11 22 44 88 176 181 191)

(power-tree 12509) ;; not optimal
Looking for 12509 in (🌴 1).
L(12509) = 18 - chain:#( 1 2 3 5 10 13 26 39 78 156 312 624 1248 2496 2509 3757 6253 12506 12509)
L(12509) = 18 - chain:#( 1 2 3 5 10 15 25 50 75 125 250 500 1000 2000 2003 4003 8006 12009 12509) 

(power-tree 222222)
Looking for 222222 in (🌴 1).
L(222222) = 22 - chain:#( 1 2 3 5 7 14 21 35 70 105 210 420 840 1680 1687 3367 6734 13468 26936 53872 57239 111111 222222) 

Exponentiation

;; j such  as chain[i] = chain[i-1] + chain[j]
(define (adder chain  i)
	(for ((j i)) #:break (= [chain i] (+ [chain(1-  i)] [chain j])) => j ))
		
		
(define (power-exp x chain)
	(define lg (vector-length chain))
	(define pow (make-vector lg x))
	(for ((i  (in-range 1 lg)))
	(vector-set! pow  i ( * [pow [1- i]] [pow (adder chain i)])))
	[pow (1- lg)])
Output:
(power-exp 2 #( 1 2 4 8 16 17) )
   → 131072
(power-exp 1.1 #( 1 2 3 5 10 20 40 41 81) )
    → 2253.2402360440283

(lib 'bigint)
bigint.lib v1.4 ® EchoLisp
Lib: bigint.lib loaded.
(power-exp 3 #( 1 2 3 5 7 14 19 38 57 95 190 191) )
    → 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347

Integer Exponentiation

// Integer exponentiation using Knuth power tree. Nigel Galloway: October 29th., 2020
let kT α=let n=Array.zeroCreate<int*int list>((pown 2 (α+1))+1)
         let fN g=let rec fN p=[yield g+p; if p>0 then let g,_=n.[p] in yield! fN g] in (g+g)::(fN (fst n.[g]))|>List.rev
         let fG g=[for α,β in g do for g in β do let p,_=n.[g] in n.[g]<-(p,fN g|>List.filter(fun β->if box n.[β]=null then n.[β]<-(g,[]); true else false)); yield n.[g]]
         let rec kT n g=match g with 0->() |_->let n=fG n in kT n (g-1)
         let fE X g=let α=let rec fE g=[|yield g; if g>1 then yield! fE (fst n.[g])|] in fE g
                    let β=Array.zeroCreate<bigint>α.Length
                    let l=β.Length-1
                    β.[l]<-bigint (X+0)
                    for e in l-1.. -1..0 do β.[e]<-match α.[e]%2 with 0->β.[e+1]*β.[e+1] |_->let l=α.[e+1] in β.[e+1]*β.[α|>Array.findIndex(fun n->l+n=α.[e])]
                    β.[0]
         n.[1]<-(0,[2]); n.[2]<-(1,[]); kT [n.[1]] α; (fun n g->if g=0 then 1I else fE n g) 
let xp=kT 11         
[0..17]|>List.iter(fun n->printfn "2**%d=%A\n" n (xp 2 n))
printfn "3**191=%A" (xp 3 191)

{out}

2**0=1
2**1=2
2**2=4
2**3=8
2**4=16
2**5=32
2**6=64
2**7=128
2**8=256
2**9=512
2**10=1024
2**11=2048
2**12=4096
2**13=8192
2**14=16384
2**15=32768
2**16=65536
2**17=131072

3**191=13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347

Float Exponentiation

// Float exponentiation using Knuth power tree. Nigel Galloway: October 29th., 2020
let kTf α=let n=Array.zeroCreate<int*int list>((pown 2 (α+1))+1)
          let fN g=let rec fN p=[yield g+p; if p>0 then let g,_=n.[p] in yield! fN g] in (g+g)::(fN (fst n.[g]))|>List.rev
          let fG g=[for α,β in g do for g in β do let p,_=n.[g] in n.[g]<-(p,fN g|>List.filter(fun β->if box n.[β]=null then n.[β]<-(g,[]); true else false)); yield n.[g]]
          let rec kT n g=match g with 0->() |_->let n=fG n in kT n (g-1)
          let fE X g=let α=let rec fE g=[|yield g; if g>1 then yield! fE (fst n.[g])|] in fE g
                     let β=Array.zeroCreate<float>α.Length
                     let l=β.Length-1
                     β.[l]<-X
                     for e in l-1.. -1..0 do β.[e]<-match α.[e]%2 with 0->β.[e+1]*β.[e+1] |_->let l=α.[e+1] in β.[e+1]*β.[α|>Array.findIndex(fun n->l+n=α.[e])]
                     β.[0]
          n.[1]<-(0,[2]); n.[2]<-(1,[]); kT [n.[1]] α; (fun n g->if g=0 then 1.0 else fE n g) 

let xpf=kTf 11
printfn "1.1**81=%f" (xpf 1.1 81)
Output:
1.1**81=2253.240236
Translation of: Inspired by Free Basic
Library: quad double
module hash_map_module

    use iso_fortran_env
    use qdmodule

    implicit none
    private
    public :: HashEntry, HashMap

    type HashEntry
        integer(int64) :: key, value
        type(HashEntry), pointer :: sgte => null()
    end type HashEntry

! Container for pointer to HashEntry
    type HashEntryContainer
        type(HashEntry), pointer :: ptr => null()
    end type HashEntryContainer

    type HashMap
        type(HashEntryContainer), allocatable :: buckets(:)
    contains
        procedure :: put => hash_map_put
        procedure :: get => hash_map_get
        procedure :: contains => hash_map_contains
    end type HashMap

contains

    subroutine hash_map_put(this, key, value)
        class(HashMap), intent(inout) :: this
        integer(int64), intent(in) :: key, value
        integer(int64) :: bucket
        type(HashEntry), pointer :: entry

        bucket = iand(key, int(255, int64))
        entry => this % buckets(bucket) % ptr

        ! Check for existing key
        do while (associated(entry))
            if (entry % key == key) then
                entry % value = value
                return
            end if
            entry => entry % sgte
        end do

        ! Insert new entry at head
        allocate (entry)
        entry % key = key
        entry % value = value
        entry % sgte => this % buckets(bucket) % ptr  ! Correct pointer assignment
        this % buckets(bucket) % ptr => entry       ! Update head pointer
    end subroutine hash_map_put

    function hash_map_get(this, key, defaultValue) result(res)
        class(HashMap), intent(in) :: this
        integer(int64), intent(in) :: key
        integer(int64), optional, intent(in) :: defaultValue
        integer(int64) :: res, bucket
        type(HashEntry), pointer :: entry

        res = 0
        if (present(defaultValue)) res = defaultValue
        bucket = iand(key, int(255, int64))
        entry => this % buckets(bucket) % ptr

        do while (associated(entry))
            if (entry % key == key) then
                res = entry % value
                return
            end if
            entry => entry % sgte
        end do
    end function hash_map_get

    function hash_map_contains(this, key) result(res)
        class(HashMap), intent(in) :: this
        integer(int64), intent(in) :: key
        logical :: res
        integer(int64) :: bucket
        type(HashEntry), pointer :: entry

        bucket = iand(key, int(255, int64))
        entry => this % buckets(bucket) % ptr

        res = .false.
        do while (associated(entry))
            if (entry % key == key) then
                res = .true.
                return
            end if
            entry => entry % sgte
        end do
    end function hash_map_contains

end module hash_map_module

module int_array_module
    use iso_fortran_env
    implicit none
    private
    public :: IntArray

    type IntArray
        integer(int64), allocatable :: dato(:)
        integer(int64) :: size = 0
    contains
        procedure :: add => int_array_add
        procedure :: get => int_array_get
        procedure :: getSize => int_array_size
        procedure :: clear => int_array_clear
    end type

contains
    subroutine int_array_add(this, value)
        use iso_fortran_env
        class(IntArray), intent(inout) :: this
        integer(int64), intent(in) :: value
        integer(int64), allocatable :: temp(:)
        integer(int64) :: current_capacity

        if (.not. allocated(this % dato)) then
            allocate (this % dato(30))
            current_capacity = 30_8
        else
            current_capacity = size(this % dato)
        end if

        if (this % size >= current_capacity) then
            call move_alloc(this % dato, temp)
            allocate (this % dato(2 * current_capacity))
            this % dato(1:this % size) = temp(1:this % size)
        end if

        this % size = this % size + 1
        this % dato(this % size) = value
    end subroutine int_array_add

    function int_array_get(this, index) result(res)
        class(IntArray), intent(in) :: this
        integer(int64), intent(in) :: index
        integer(int64) :: res

        res = 0
        if (index >= 1 .and. index <= this % size) res = this % dato(index)
    end function

    function int_array_size(this) result(res)
        use iso_fortran_env
        class(IntArray), intent(in) :: this
        integer(int64) :: res
        res = this % size
    end function

    subroutine int_array_clear(this)
        class(IntArray), intent(inout) :: this
        this % size = 0
    end subroutine
end module

module power_module
    use iso_fortran_env
    use hash_map_module
    use int_array_module
    implicit none
    private
    public :: showPow, initialize_power  ! Add initialization routine

    type(HashMap) :: p
    type(IntArray) :: levels(1)

contains

    subroutine initialize_power
        integer :: i
        if (allocated(p % buckets)) deallocate (p % buckets)
        allocate (p % buckets(0:255))
        do i = 0, 255
            nullify (p % buckets(i) % ptr)  ! Explicitly nullify all bucket pointers
        end do
        call levels(1) % clear()
        call p % put(1_8, 0_8)
        call levels(1) % add(1_8)
    end subroutine

    recursive function path(n) result(res)
        use iso_fortran_env
        use hash_map_module
        use int_array_module
        implicit none
        integer(int64), intent(in) :: n
        type(IntArray) :: res
        integer(int64) :: i, j, x, y, sum, curr
        type(IntArray) :: q, tempPath
        integer(int64) :: max_iter, iter

        ! Safety limit to prevent infinite loops
        max_iter = 100000000
        iter = 0

        if (n == 0) return
        do while (.not. p % contains(n))
            q = IntArray()

            do i = 1, levels(1) % getSize()
                x = levels(1) % get(i)
                associate (xPath => path(x))
                    do j = 1, xPath % getSize()
                        y = xPath % get(j)
                        sum = x + y
                        if (p % contains(sum)) cycle
                        call p % put(sum, x)
                        call q % add(sum)
                    end do
                end associate
            end do
            call levels(1) % clear()
            do i = 1, q % getSize()
                call levels(1) % add(q % get(i))
            end do

            if (q % getSize() == 0) exit

            iter = iter + 1
            if (iter > max_iter) then
                print *, "Path search exceeded maximum iterations for n=", n
                exit
            end if
        end do

        curr = n
        tempPath = IntArray()

        do while (curr /= 0)
            call tempPath % add(curr)
            curr = p % get(curr, 0_8)
        end do

        do i = tempPath % getSize(), 1, -1
            call res % add(tempPath % get(i))
        end do

        return
    end function path

    function treePowBig(x, n) result(res)
        use iso_fortran_env
        integer(int64), intent(in) :: x, n
        integer(kind=16) :: res
        integer(kind=16), allocatable :: r(:)
        integer(int64) :: i, curr, p
        type(IntArray) :: pathToN

        ! Allocate array to hold intermediate results
        allocate (r(0:n))
        r(0) = 1_16
        if (n >= 1) r(1) = x

        p = 0
        pathToN = path(n)

        do i = 1, pathToN % getSize()
            curr = pathToN % get(i)
            r(curr) = r(curr - p) * r(p)
            p = curr
        end do

        res = r(n)
        deallocate (r)
    end function treePowBig

    function treePowDecimal(x, n) result(res)
        use qdmodule
        type(qd_real), intent(in) :: x
        integer(int64), intent(in) :: n
        type(qd_real) :: res
        type(qd_real), allocatable :: r(:)
        integer(int64) :: i, curr, p
        type(IntArray) :: pathToN

        allocate (r(0:n))
        r(0) = "1.0"  ! r(0) = 1.0 in quad-double
        if (n >= 1) r(1) = x

        p = 0
        pathToN = path(n)
        do i = 1, pathToN % getSize()
            curr = pathToN % get(i)
            r(curr) = r(curr - p) * r(p)
            p = curr
        end do

        res = r(n)
        deallocate (r)
    end function treePowDecimal

    subroutine showPow(x, n, xx)
        use iso_fortran_env
        use qdmodule
        use int_array_module
        implicit none
        character(len=*) :: xx
        type(qd_real), intent(in) :: x
        integer(int64), intent(in) :: n
        type(IntArray) :: pathToN
        character(len=1024) :: pathStr
        integer(int64) :: i
        type(qd_real) :: result
        character(len=1024) :: str
        character(len=5) :: str2
        double precision :: try
        integer :: unit
!
        pathToN = path(n)
        pathStr = ""
        do i = 1, pathToN % getSize()
            if (i > 1) pathStr = trim(pathStr)//", "
            write (pathStr(len_trim(pathStr) + 1:), '(I0)') pathToN % get(i)
        end do

        print '(I0,": [",A,"]" )', n, trim(pathStr)

        result = treePowDecimal(x, n)
!    call qdwrite(6, result)  ! Writes result to stdout (unit 6)

        ! Create a temporary internal file (string)
        open (newunit=unit, status='scratch', action='readwrite', form='formatted')

        ! Write qd_real to the internal file
        call qdwrite(unit, result)

        ! Read back into the string
        rewind (unit)
        read (unit, '(A)') str
        close (unit)
        write (str2, '(i0)') n
        write (*, '(a)', advance="no") 'Result: '//xx//'^'//trim(adjustl(str2))//' = '
        read (str, *) try
        if ((mod(try, 1.0) == 0.0) .and. (try < real(huge(1_16), kind=real64))) then
            write (str, '(I0)') int(try, kind=16)
            write (*, '(A)') trim(adjustl(str))
        else
            if (try < 1.0d10) then
                write (str, '(f20.13)') try
                write (*, '(a)') trim(adjustl(str))
            else
                write (*, '(a)') trim(adjustl(str))
            end if
        end if
        print *
    end subroutine showPow

end module

program main
    use iso_fortran_env
    use qdmodule
    use power_module
    implicit none
    integer(int64) :: i
    type(qd_real) :: x

    call initialize_power()

    x = "2.0"
    do i = 0, 17
        call showPow(x, i, "2.0")
    end do

    x = "1.1"
    call showPow(x, 81_8, "1.1")
    call initialize_power()

    x = "3.0"
    call showPow(x, 191_8, "3.0")

    stop 'Normal Finish'
end program
Output:
0: []
Result: 2.0^0 = 1

1: [1]
Result: 2.0^1 = 2

2: [1,2]
Result: 2.0^2 = 4

3: [1,2,3]
Result: 2.0^3 = 8

4: [1,2,4]
Result: 2.0^4 = 16

5: [1,2,3,5]
Result: 2.0^5 = 32

6: [1,2,3,6]
Result: 2.0^6 = 64

7: [1,2,3,5,7]
Result: 2.0^7 = 128

8: [1,2,4,8]
Result: 2.0^8 = 256

9: [1,2,3,6,9]
Result: 2.0^9 = 512

10: [1,2,3,5,10]
Result: 2.0^10 = 1024

11: [1,2,3,5,10,11]
Result: 2.0^11 = 2048

12: [1,2,3,6,12]
Result: 2.0^12 = 4096

13: [1,2,3,5,10,13]
Result: 2.0^13 = 8192

14: [1,2,3,5,7,14]
Result: 2.0^14 = 16384

15: [1,2,3,5,10,15]
Result: 2.0^15 = 32768

16: [1,2,4,8,16]
Result: 2.0^16 = 65536

17: [1,2,4,8,16,17]
Result: 2.0^17 = 131072

81: [1,2,3,5,10,20,40,41,81]
Result: 1.1^81 = 2253.2402360440124

191: [1,2,3,5,7,14,19,38,57,95,190,191]
Result: 3.0^191 = 1.34945886742810938037281573965238849174025022940301019140667054E+91

Library: big_integer
#include once "big_int\big_integer.bi"

Const NULL As Any Ptr = 0

Type HashEntry
    key As Integer
    value As Integer
    sgte As HashEntry Ptr
End Type

Type HashMap
    buckets(255) As HashEntry Ptr
    
    Declare Sub put(key As Integer, value As Integer)
    Declare Function get(key As Integer, defaultValue As Integer = 0) As Integer
    Declare Function contains(key As Integer) As Boolean
End Type

Sub HashMap.put(key As Integer, value As Integer)
    Dim As Integer bucket = key And 255
    Dim As HashEntry Ptr entry = buckets(bucket)
    
    ' Check if key already exists
    While entry <> NULL
        If entry->key = key Then
            entry->value = value
            Exit Sub
        End If
        entry = entry->sgte
    Wend
    
    ' Create new entry
    entry = New HashEntry
    entry->key = key
    entry->value = value
    entry->sgte = buckets(bucket)
    buckets(bucket) = entry
End Sub

Function HashMap.get(key As Integer, defaultValue As Integer = 0) As Integer
    Dim As Integer bucket = key And 255
    Dim As HashEntry Ptr entry = buckets(bucket)
    
    While entry <> NULL
        If entry->key = key Then Return entry->value
        entry = entry->sgte
    Wend
    
    Return defaultValue
End Function

Function HashMap.contains(key As Integer) As Boolean
    Dim As Integer bucket = key And 255
    Dim As HashEntry Ptr entry = buckets(bucket)
    
    While entry <> NULL
        If entry->key = key Then Return True
        entry = entry->sgte
    Wend
    
    Return False
End Function

Type IntArray
    dato As Integer Ptr
    size As Integer
    capacity As Integer
    
    Declare Sub add(value As Integer)
    Declare Function get(index As Integer) As Integer
    Declare Function getSize() As Integer
    Declare Sub clear()
End Type

Sub IntArray.add(value As Integer)
    If size >= capacity Then
        capacity = Iif(capacity = 0, 8, capacity * 2)
        Dim As Integer Ptr newdato = New Integer[capacity]
        If dato <> NULL Then
            For i As Integer = 0 To size - 1
                newdato[i] = dato[i]
            Next
            Delete[] dato
        End If
        dato = newdato
    End If
    
    dato[size] = value
    size += 1
End Sub

Function IntArray.get(index As Integer) As Integer
    If index >= 0 And index < size Then Return dato[index]
    Return 0
End Function

Function IntArray.getSize() As Integer
    Return size
End Function

Sub IntArray.clear()
    size = 0
End Sub

' Global variables
Dim Shared As HashMap p
Dim Shared As IntArray levels(0)  ' Array of levels

' Function to compute the path to n
Function path(n As Integer) As IntArray
    Dim As Integer i, j, x, y, sum
    Dim As IntArray result
    
    ' Base case
    If n = 0 Then Return result
    
    ' Check if we already have a path to n
    While Not p.contains(n)
        Dim q As IntArray
        
        ' Process current level
        For i = 0 To levels(0).getSize() - 1
            x = levels(0).get(i)
            
            ' Get path to x
            Dim As IntArray xPath = path(x)
            
            ' Try to extend the path
            For j = 0 To xPath.getSize() - 1
                y = xPath.get(j)
                sum = x + y
                
                ' Check if we already have a path to sum
                If p.contains(sum) Then Exit For
                
                ' Record the path
                p.put(sum, x)
                q.add(sum)
            Next j
        Next i
        
        ' Update level
        levels(0).clear()
        For i = 0 To q.getSize() - 1
            levels(0).add(q.get(i))
        Next i
        
        ' If we can't make progress, break
        If q.getSize() = 0 Then Exit While
    Wend
    
    ' Reconstruct the path
    Dim As Integer curr = n
    Dim As IntArray tempPath
    
    While curr <> 0
        tempPath.add(curr)
        curr = p.get(curr)
    Wend
    
    ' Reverse the path
    For i = tempPath.getSize() - 1 To 0 Step -1
        result.add(tempPath.get(i))
    Next i
    
    Return result
End Function

' Function to compute x^n using the tree method with BigInteger for integers
Function treePowBig(x As Integer, n As Integer) As BigInt
    Dim As BigInt r(0 To n)   
    ' Initialize r[0] = 1 and r[1] = x
    r(0) = 1
    r(1) = x
    
    Dim As Integer i, curr, p = 0
    Dim As IntArray pathToN = path(n)
    
    For i = 0 To pathToN.getSize() - 1
        curr = pathToN.get(i)
        r(curr) = r(curr - p) * r(p)
        p = curr
    Next i
    
    Return r(n)
End Function

' Function to compute x^n using the tree method with high precision for decimals
Function treePowDecimal(x As Double, n As Integer) As Double
    Dim As Double r(0 To n)
    ' Initialize r[0] = 1 and r[1] = x
    r(0) = 1
    r(1) = x
    
    Dim As Integer i, curr, p = 0
    Dim As IntArray pathToN = path(n)
    
    For i = 0 To pathToN.getSize() - 1
        curr = pathToN.get(i)
        r(curr) = r(curr - p) * r(p)
        p = curr
    Next i
    
    Return r(n)
End Function

' Function to display the power calculation
Sub showPow(x As Double, n As Integer)
    Dim As IntArray pathToN = path(n)
    Dim As String pathStr = ""
    
    For i As Integer = 0 To pathToN.getSize() - 1
        If i > 0 Then pathStr &= ", "
        pathStr &= Str(pathToN.get(i))
    Next i
    
    Print n & ": [" & pathStr & "]"
    
    If Int(x) = x And n > 20 Then
        ' Use BigInt for large integer powers
        Dim As BigInt result = treePowBig(Int(x), n)
        Print x & "^" & n & " = " & result
    Elseif Int(x) <> x Then
        ' Use high precision for decimal numbers
        Dim As Double result = treePowDecimal(x, n)
        Print Using "##.#^## = ####.######"; x; n; result
    Else
        ' Use standard calculation for small integer powers
        Dim As Double result = treePowDecimal(x, n)
        Print Using "##^## = &"; Int(x); n; result
    End If
    Print
End Sub

' Initialize
p.put(1, 0)
levels(0).add(1)

' Main program
For i As Integer = 0 To 17
    showPow(2, i)
Next i

showPow(1.1, 81)
showPow(3, 191)

Sleep
Output:
0: []
 2^ 0 = 1

1: [1]
 2^ 1 = 2

2: [1, 2]
 2^ 2 = 4

3: [1, 2, 3]
 2^ 3 = 8

4: [1, 2, 4]
 2^ 4 = 16

5: [1, 2, 4, 5]
 2^ 5 = 32

6: [1, 2, 4, 6]
 2^ 6 = 64

7: [1, 2, 4, 6, 7]
 2^ 7 = 128

8: [1, 2, 4, 8]
 2^ 8 = 256

9: [1, 2, 4, 8, 9]
 2^ 9 = 512

10: [1, 2, 4, 8, 10]
 2^10 = 1024

11: [1, 2, 4, 8, 10, 11]
 2^11 = 2048

12: [1, 2, 4, 8, 12]
 2^12 = 4096

13: [1, 2, 4, 8, 12, 13]
 2^13 = 8192

14: [1, 2, 4, 8, 12, 14]
 2^14 = 16384

15: [1, 2, 4, 8, 12, 14, 15]
 2^15 = 32768

16: [1, 2, 4, 8, 16]
 2^16 = 65536

17: [1, 2, 4, 8, 16, 17]
 2^17 = 131072

81: [1, 2, 4, 8, 16, 32, 64, 80, 81]
 1.1^81 = 2253.240236

191: [1, 2, 4, 8, 16, 32, 64, 128, 160, 176, 184, 188, 190, 191]
3^191 = +13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
Translation of: Kotlin
package main

import (
    "fmt"
    "math/big"
)

var (
    p   = map[int]int{1: 0}
    lvl = [][]int{[]int{1}}
)

func path(n int) []int {
    if n == 0 {
        return []int{}
    }
    for {
        if _, ok := p[n]; ok {
            break
        }
        var q []int
        for _, x := range lvl[0] {
            for _, y := range path(x) {
                z := x + y
                if _, ok := p[z]; ok {
                    break
                }
                p[z] = x
                q = append(q, z)
            }
        }
        lvl[0] = q
    }
    r := path(p[n])
    r = append(r, n)
    return r
}

func treePow(x float64, n int) *big.Float {
    r := map[int]*big.Float{0: big.NewFloat(1), 1: big.NewFloat(x)}
    p := 0
    for _, i := range path(n) {
        temp := new(big.Float).SetPrec(320)
        temp.Mul(r[i-p], r[p])
        r[i] = temp
        p = i
    }
    return r[n]
}

func showPow(x float64, n int, isIntegral bool) {
    fmt.Printf("%d: %v\n", n, path(n))
    f := "%f"
    if isIntegral {
        f = "%.0f"
    }
    fmt.Printf(f, x)
    fmt.Printf(" ^ %d = ", n)
    fmt.Printf(f+"\n\n", treePow(x, n))
}

func main() {
    for n := 0; n <= 17; n++ {
        showPow(2, n, true)
    }
    showPow(1.1, 81, false)
    showPow(3, 191, true)
}
Output:
0: []
2 ^ 0 = 1

1: [1]
2 ^ 1 = 2

2: [1 2]
2 ^ 2 = 4

3: [1 2 3]
2 ^ 3 = 8

4: [1 2 4]
2 ^ 4 = 16

5: [1 2 4 5]
2 ^ 5 = 32

6: [1 2 4 6]
2 ^ 6 = 64

7: [1 2 4 6 7]
2 ^ 7 = 128

8: [1 2 4 8]
2 ^ 8 = 256

9: [1 2 4 8 9]
2 ^ 9 = 512

10: [1 2 4 8 10]
2 ^ 10 = 1024

11: [1 2 4 8 10 11]
2 ^ 11 = 2048

12: [1 2 4 8 12]
2 ^ 12 = 4096

13: [1 2 4 8 12 13]
2 ^ 13 = 8192

14: [1 2 4 8 12 14]
2 ^ 14 = 16384

15: [1 2 4 8 12 14 15]
2 ^ 15 = 32768

16: [1 2 4 8 16]
2 ^ 16 = 65536

17: [1 2 4 8 16 17]
2 ^ 17 = 131072

81: [1 2 4 8 16 32 64 80 81]
1.100000 ^ 81 = 2253.240236

191: [1 2 4 8 16 32 64 128 160 176 184 188 190 191]
3 ^ 191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
Translation of: Java
class PowerTree {
    private static Map<Integer, Integer> p = new HashMap<>()
    private static List<List<Integer>> lvl = new ArrayList<>()

    static {
        p[1] = 0

        List<Integer> temp = new ArrayList<Integer>()
        temp.add 1
        lvl.add temp
    }

    private static List<Integer> path(int n) {
        if (n == 0) return new ArrayList<Integer>()
        while (!p.containsKey(n)) {
            List<Integer> q = new ArrayList<>()
            for (Integer x in lvl.get(0)) {
                for (Integer y in path(x)) {
                    if (p.containsKey(x + y)) break
                    p[x + y] = x
                    q.add x + y
                }
            }
            lvl[0].clear()
            lvl[0].addAll q
        }
        List<Integer> temp = path p[n]
        temp.add n
        temp
    }

    private static BigDecimal treePow(double x, int n) {
        Map<Integer, BigDecimal> r = new HashMap<>()
        r[0] = BigDecimal.ONE
        r[1] = BigDecimal.valueOf(x)

        int p = 0
        for (Integer i in path(n)) {
            r[i] = r[i - p] * r[p]
            p = i
        }
        r[n]
    }

    private static void showPos(double x, int n, boolean isIntegral) {
        printf("%d: %s\n", n, path(n))
        String f = isIntegral ? "%.0f" : "%f"
        printf(f, x)
        printf(" ^ %d = ", n)
        printf(f, treePow(x, n))
        println()
        println()
    }

    static void main(String[] args) {
        for (int n = 0; n <= 17; ++n) {
            showPos 2.0, n, true
        }
        showPos 1.1, 81, false
        showPos 3.0, 191, true
    }
}
Output:
0: []
2 ^ 0 = 1

1: [1]
2 ^ 1 = 2

2: [1, 2]
2 ^ 2 = 4

3: [1, 2, 3]
2 ^ 3 = 8

4: [1, 2, 4]
2 ^ 4 = 16

5: [1, 2, 4, 5]
2 ^ 5 = 32

6: [1, 2, 4, 6]
2 ^ 6 = 64

7: [1, 2, 4, 6, 7]
2 ^ 7 = 128

8: [1, 2, 4, 8]
2 ^ 8 = 256

9: [1, 2, 4, 8, 9]
2 ^ 9 = 512

10: [1, 2, 4, 8, 10]
2 ^ 10 = 1024

11: [1, 2, 4, 8, 10, 11]
2 ^ 11 = 2048

12: [1, 2, 4, 8, 12]
2 ^ 12 = 4096

13: [1, 2, 4, 8, 12, 13]
2 ^ 13 = 8192

14: [1, 2, 4, 8, 12, 14]
2 ^ 14 = 16384

15: [1, 2, 4, 8, 12, 14, 15]
2 ^ 15 = 32768

16: [1, 2, 4, 8, 16]
2 ^ 16 = 65536

17: [1, 2, 4, 8, 16, 17]
2 ^ 17 = 131072

81: [1, 2, 4, 8, 16, 32, 64, 80, 81]
1.100000 ^ 81 = 2253.240236

191: [1, 2, 4, 8, 16, 32, 64, 128, 160, 176, 184, 188, 190, 191]
3 ^ 191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
Works with: GHC version 8.8.1
Library: containers version 0.6.2.1
{-# LANGUAGE ScopedTypeVariables #-}

module Rosetta.PowerTree
    ( Natural
    , powerTree
    , power
    )  where

import           Data.Foldable (toList)
import           Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import           Data.Maybe (fromMaybe)
import           Data.List (foldl')
import           Data.Sequence (Seq (..), (|>))
import qualified Data.Sequence as Seq
import           Numeric.Natural (Natural)

type M = Map Natural S
type S = Seq Natural

levels :: [M]
levels = let s = Seq.singleton 1 in fst <$> iterate step (Map.singleton 1 s, s)

step :: (M, S) -> (M, S)
step (m, xs) = foldl' f (m, Empty) xs
  where
    f :: (M, S) -> Natural -> (M, S)
    f (m', ys) n = foldl' g (m', ys) ns
      where
        ns :: S
        ns = m' Map.! n

        g :: (M, S) -> Natural -> (M, S)
        g (m'', zs) k =
            let l = n + k
            in  case Map.lookup l m'' of
                    Nothing -> (Map.insert l (ns |>  l) m'', zs |> l)
                    Just _  -> (m'', zs)

powerTree :: Natural -> [Natural]
powerTree n
    | n <= 0    = []
    | otherwise = go levels
  where
    go :: [M] -> [Natural]
    go []       = error "impossible branch"
    go (m : ms) = fromMaybe (go ms) $ toList <$> Map.lookup n m

power :: forall a. Num a => a -> Natural -> a
power _ 0 = 1
power a n = go a 1 (Map.singleton 1 a) $ tail $ powerTree n
  where
    go :: a -> Natural -> Map Natural a -> [Natural] -> a
    go b _ _ []       = b
    go b k m (l : ls) =
        let b' = b * m Map.! (l - k)
            m' = Map.insert l b' m
        in  go b' l m' ls
Output:
Library: numbers version 3000.2.0.2

(The CReal type from package numbers is used to get the exact result for the last example.)

powerTree 0 = [], power 2 0 = 1
powerTree 1 = [1], power 2 1 = 2
powerTree 2 = [1,2], power 2 2 = 4
powerTree 3 = [1,2,3], power 2 3 = 8
powerTree 4 = [1,2,4], power 2 4 = 16
powerTree 5 = [1,2,3,5], power 2 5 = 32
powerTree 6 = [1,2,3,6], power 2 6 = 64
powerTree 7 = [1,2,3,5,7], power 2 7 = 128
powerTree 8 = [1,2,4,8], power 2 8 = 256
powerTree 9 = [1,2,3,6,9], power 2 9 = 512
powerTree 10 = [1,2,3,5,10], power 2 10 = 1024
powerTree 11 = [1,2,3,5,10,11], power 2 11 = 2048
powerTree 12 = [1,2,3,6,12], power 2 12 = 4096
powerTree 13 = [1,2,3,5,10,13], power 2 13 = 8192
powerTree 14 = [1,2,3,5,7,14], power 2 14 = 16384
powerTree 15 = [1,2,3,5,10,15], power 2 15 = 32768
powerTree 16 = [1,2,4,8,16], power 2 16 = 65536
powerTree 17 = [1,2,4,8,16,17], power 2 17 = 131072
powerTree 191 = [1,2,3,5,7,14,19,38,57,95,190,191], power 3 191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
powerTree 81 = [1,2,3,5,10,20,40,41,81], power 1.1 81 = 2253.240236044012487937308538033349567966729852481170503814810577345406584190098644811

J

Generally, this task should be accomplished in J using x^n . Here we take an approach that's more comparable with the other examples on this page.

This task is a bit verbose...

We can represent the tree as a list of indices. Each entry in the list gives the value of n for the index a+n. (We can find a using subtraction.)

knuth_power_tree=:3 :0
  L=: P=: %(1+y){._ 1
  findpath=: ]
  while. _ e.P do.
    for_n.(/: findpath&>)I.L=>./L-._ do.
      for_a. findpath n do.
         j=. n+a
         l=. 1+n{L
         if. j>y do. break. end.
         if. l>:j{ L do. continue. end.
         L=: l j} L
         P=: n j} P
      end.
      findpath=: [: |. {&P^:a:
    end.
  end.
  P
)

usepath=:4 :0
  path=. findpath y
  exp=. 1,({:path)#x
  for_ex.(,.~2 -~/\"1])2 ,\path  do.
    'ea eb ec'=. ex
    exp=.((ea{exp)*eb{exp) ec} exp
  end.
  {:exp
)

Task examples:

   knuth_power_tree 191 NB. generate sufficiently large tree
0 1 1 2 2 3 3 5 4 6 5 10 6 10 7 10 8 16 9 14 10 14 11 13 12 15 13 18 14 28 15 28 16 17 17 21 18 36 19 26 20 40 21 40 22 30 23 42 24 48 25 48 26 52 27 44 28 38 29 31 30 56 31 42 32 64 33 66 34 46 35 57 36 37 37 50 38 76 39 76 40 41 41 43 42 80 43 84 44 47 45 70 46 62 47 57 48 49 49 51 50 100 51 100 52 70 53 104 54 104 55 108 56 112 57 112 58 61 59 112 60 120 61 120 62 75 63 126 64 65 65 129 66 67 67 90 68 136 69 138 70 140 71 140 72 144 73 144 74 132 75 138 76 144 77 79 78 152 79 152 80 160 81 160 82 85 83 162 84 168 85 114 86 168 87 105 88 118 89 176 90 176 91 122 92 184 93 176 94 126 95 190

   findpath 0
0
   2 usepath 0
1

   findpath 1
1
   2 usepath 1
2

   findpath 2
1 2
   2 usepath 2
4

   findpath 3
1 2 3
   2 usepath 3
8

   findpath 4
1 2 4
   2 usepath 4
16

   findpath 5
1 2 3 5
   2 usepath 5
32

   findpath 6
1 2 3 6
   2 usepath 6
64

   findpath 7
1 2 3 5 7
   2 usepath 7
128

   findpath 8
1 2 4 8
   2 usepath 8
256

   findpath 9
1 2 3 6 9
   2 usepath 9
512

   findpath 10
1 2 3 5 10
   2 usepath 10
1024

   findpath 11
1 2 3 5 10 11
   2 usepath 11
2048

   findpath 12
1 2 3 6 12
   2 usepath 12
4096

   findpath 13
1 2 3 5 10 13
   2 usepath 13
8192

   findpath 14
1 2 3 5 7 14
   2 usepath 14
16384

   findpath 15
1 2 3 5 10 15
   2 usepath 15
32768

   findpath 16
1 2 4 8 16
   2 usepath 16
65536

   findpath 17
1 2 4 8 16 17
   2 usepath 17
131072

   findpath 191
1 2 3 5 7 14 19 38 57 95 190 191
   3x usepath 191
13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347

   findpath 81
1 2 3 5 10 20 40 41 81
   (x:1.1) usepath 81
2253240236044012487937308538033349567966729852481170503814810577345406584190098644811r1000000000000000000000000000000000000000000000000000000000000000000000000000000000

Note that an 'r' in a number indicates a rational number with the numerator to the left of the r and the denominator to the right of the r. We could instead use decimal notation by indicating how many characters of result we want to see, as well as how many characters to the right of the decimal point we want to see.

Thus, for example:

   90j83 ": (x:1.1) usepath 81
  2253.24023604401248793730853803334956796672985248117050381481057734540658419009864481100
Translation of: Kotlin
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PowerTree {
    private static Map<Integer, Integer> p = new HashMap<>();
    private static List<List<Integer>> lvl = new ArrayList<>();

    static {
        p.put(1, 0);

        ArrayList<Integer> temp = new ArrayList<>();
        temp.add(1);
        lvl.add(temp);
    }

    private static List<Integer> path(int n) {
        if (n == 0) return new ArrayList<>();
        while (!p.containsKey(n)) {
            List<Integer> q = new ArrayList<>();
            for (Integer x : lvl.get(0)) {
                for (Integer y : path(x)) {
                    if (p.containsKey(x + y)) break;
                    p.put(x + y, x);
                    q.add(x + y);
                }
            }
            lvl.get(0).clear();
            lvl.get(0).addAll(q);
        }
        List<Integer> temp = path(p.get(n));
        temp.add(n);
        return temp;
    }

    private static BigDecimal treePow(double x, int n) {
        Map<Integer, BigDecimal> r = new HashMap<>();
        r.put(0, BigDecimal.ONE);
        r.put(1, BigDecimal.valueOf(x));

        int p = 0;
        for (Integer i : path(n)) {
            r.put(i, r.get(i - p).multiply(r.get(p)));
            p = i;
        }
        return r.get(n);
    }

    private static void showPow(double x, int n, boolean isIntegral) {
        System.out.printf("%d: %s\n", n, path(n));
        String f = isIntegral ? "%.0f" : "%f";
        System.out.printf(f, x);
        System.out.printf(" ^ %d = ", n);
        System.out.printf(f, treePow(x, n));
        System.out.println("\n");
    }

    public static void main(String[] args) {
        for (int n = 0; n <= 17; ++n) {
            showPow(2.0, n, true);
        }
        showPow(1.1, 81, false);
        showPow(3.0, 191, true);
    }
}
Output:
0: []
2 ^ 0 = 1

1: [1]
2 ^ 1 = 2

2: [1, 2]
2 ^ 2 = 4

3: [1, 2, 3]
2 ^ 3 = 8

4: [1, 2, 4]
2 ^ 4 = 16

5: [1, 2, 4, 5]
2 ^ 5 = 32

6: [1, 2, 4, 6]
2 ^ 6 = 64

7: [1, 2, 4, 6, 7]
2 ^ 7 = 128

8: [1, 2, 4, 8]
2 ^ 8 = 256

9: [1, 2, 4, 8, 9]
2 ^ 9 = 512

10: [1, 2, 4, 8, 10]
2 ^ 10 = 1024

11: [1, 2, 4, 8, 10, 11]
2 ^ 11 = 2048

12: [1, 2, 4, 8, 12]
2 ^ 12 = 4096

13: [1, 2, 4, 8, 12, 13]
2 ^ 13 = 8192

14: [1, 2, 4, 8, 12, 14]
2 ^ 14 = 16384

15: [1, 2, 4, 8, 12, 14, 15]
2 ^ 15 = 32768

16: [1, 2, 4, 8, 16]
2 ^ 16 = 65536

17: [1, 2, 4, 8, 16, 17]
2 ^ 17 = 131072

81: [1, 2, 4, 8, 16, 32, 64, 80, 81]
1.100000 ^ 81 = 2253.240236

191: [1, 2, 4, 8, 16, 32, 64, 128, 160, 176, 184, 188, 190, 191]
3 ^ 191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347


Translation of: C++
Works with: NodeJS version 16.14.2
class PowerTree {
    static p = new Map();
    static lvl = [];

    static {
        PowerTree.p.set(1, 0);

        let temp = [1];
        PowerTree.lvl.push(temp);
    }

    static path(n) {
        if (n === 0) return [];
        while (!PowerTree.p.has(n)) {
            let q = [];
            for (let x of PowerTree.lvl[0]) {
                for (let y of PowerTree.path(x)) {
                    if (PowerTree.p.has(x + y)) break;
                    PowerTree.p.set(x + y, x);
                    q.push(x + y);
                }
            }
            PowerTree.lvl[0] = [...q]; // Important: create a new array!  Otherwise, the original array is mutated.
        }
        let temp = PowerTree.path(PowerTree.p.get(n));
        temp.push(n);
        return temp;
    }

    static treePow(x, n) {
        const r = new Map();
        r.set(0, 1n);  // Changed to bigint for accurate integer results
        r.set(1, BigInt(Math.round(x)));  // Convert to BigInt


        if (Number.isInteger(x) && Number.isInteger(n) && n>30){
             r.set(0, 1n);
             r.set(1, BigInt(x));
        } else {
            r.set(0, 1);
             r.set(1, x);
        }


        let p = 0;
        const path_result = PowerTree.path(n);

        for (let i of path_result) {
            let a = r.get(i - p);
            let b = r.get(p);

             if (Number.isInteger(x) && Number.isInteger(n) && n>30){
                r.set(i, a * b);
             } else {

                 if (typeof a === 'bigint' && typeof b === 'bigint'){
                      r.set(i, Number(a) * Number(b));
                 } else if (typeof a === 'bigint'){
                      r.set(i, Number(a) * b);
                 } else if (typeof b === 'bigint'){
                     r.set(i, a * Number(b));
                 } else {
                      r.set(i, a * b);
                 }
             }


            p = i;
        }

        if (Number.isInteger(x) && Number.isInteger(n) && n>30){
           return Number(r.get(n));
        }
        return r.get(n);
    }


    static showPow(x, n, isIntegral) {
        console.log(`${n}: ${PowerTree.path(n)}`);
        let f = isIntegral ? "%.0f" : "%f";
        //console.log(f, x); // Javascript doesn't have printf-style formatting built in

        let formatted_x;
        if (isIntegral) {
            formatted_x = Math.round(x);
        } else {
            formatted_x = x.toFixed(6); // Or whatever precision you need.
        }

        console.log(`${formatted_x} ^ ${n} = ${PowerTree.treePow(x, n)}`);
        console.log("\n");
    }

    static main() {
        for (let n = 0; n <= 17; ++n) {
            PowerTree.showPow(2.0, n, true);
        }
         PowerTree.showPow(1.1, 81, false);
        PowerTree.showPow(3.0, 191, true);
    }
}

PowerTree.main();
Output:
0: 
2 ^ 0 = 1


1: 1
2 ^ 1 = 2


2: 1,2
2 ^ 2 = 4


3: 1,2,3
2 ^ 3 = 8


4: 1,2,4
2 ^ 4 = 16


5: 1,2,4,5
2 ^ 5 = 32


6: 1,2,4,6
2 ^ 6 = 64


7: 1,2,4,6,7
2 ^ 7 = 128


8: 1,2,4,8
2 ^ 8 = 256


9: 1,2,4,8,9
2 ^ 9 = 512


10: 1,2,4,8,10
2 ^ 10 = 1024


11: 1,2,4,8,10,11
2 ^ 11 = 2048


12: 1,2,4,8,12
2 ^ 12 = 4096


13: 1,2,4,8,12,13
2 ^ 13 = 8192


14: 1,2,4,8,12,14
2 ^ 14 = 16384


15: 1,2,4,8,12,14,15
2 ^ 15 = 32768


16: 1,2,4,8,16
2 ^ 16 = 65536


17: 1,2,4,8,16,17
2 ^ 17 = 131072


81: 1,2,4,8,16,32,64,80,81
1.100000 ^ 81 = 2253.240236044025


191: 1,2,4,8,16,32,64,128,160,176,184,188,190,191
3 ^ 191 = 1.3494588674281094e+91



Adapted from #Wren

Works with jq (*)

Works with gojq, the Go implementation of jq

(*) Use gojq for infinite-precision integer arithmetic.

# Input: {p, lvl, path}
def kpath($n):
  if $n == 0 then .path=[]
  else until( .p[$n|tostring];
        .q = []
        | reduce .lvl[0][] as $x (.;
             kpath($x)
             | label $out
             | foreach (.path[], null) as $y (.;
                if $y == null then .
                else (($x + $y)|tostring) as $xy
                | if .p[$xy] then .
                  else .p[$xy] = $x 
                  | .q += [$x + $y]
                  end
                end;
                select($y == null) ) )
        | .lvl[0] = .q )
  | kpath(.p[$n|tostring])
  | .path += [$n]
  end ;

# Input: as for kpath
def treePow($x; $n):
  reduce kpath($n).path[] as $i (
    {r: { "0": 1, "1": $x }, pp: 0 };
    .r[$i|tostring] = .r[($i - .pp)|tostring] * .r[.pp|tostring]
    | .pp = $i )
  | .r[$n|tostring] ;
 
def showPow($x; $n):
  {  p: {"1": 0},
   lvl: [[1]],
   path: []}
  | "\($n): \(kpath($n).path)",
    "\($x) ^ \($n) = \(treePow($x; $n))";

 
(range(0;18) as $n | showPow(2; $n)),
showPow(1.1; 81),
showPow(3; 191)
Output:

Using gojq, the output is the same as for Wren.

Translation of: Java

Module:

module KnuthPowerTree

const p = Dict(1 => 0)
const lvl = [[1]]

function path(n)
    global p, lvl
    iszero(n) && return Int[]
    while n  keys(p)
        q = Int[]
        for x in lvl[1], y in path(x)
            if (x + y)  keys(p)
                p[x + y] = x
                push!(q, x + y)
            end
        end
        lvl[1] = q
    end
    return push!(path(p[n]), n)
end

function pow(x::Number, n::Integer)
    r = Dict{typeof(n), typeof(x)}(0 => 1, 1 => x)
    p = 0
    for i in path(n)
        r[i] = r[i - p] * r[p]
        p = i
    end
    return r[n]
end

end  # module KnuthPowerTree

Main:

using .KnuthPowerTree: path, pow

for n in 0:17
    println("2 ^ $n:\n - path: ", join(path(n), ", "), "\n - result: ", pow(2, n))
end

for (x, n) in ((big(3), 191), (1.1, 81))
    println("$x ^ $n:\n - path: ", join(path(n), ", "), "\n - result: ", pow(x, n))
end
Output:
2 ^ 0:
 - path:
 - result: 1
2 ^ 1:
 - path: 1
 - result: 2
2 ^ 2:
 - path: 1, 2
 - result: 4
2 ^ 3:
 - path: 1, 2, 3
 - result: 8
2 ^ 4:
 - path: 1, 2, 4
 - result: 16
2 ^ 5:
 - path: 1, 2, 3, 5
 - result: 32
2 ^ 6:
 - path: 1, 2, 3, 6
 - result: 64
2 ^ 7:
 - path: 1, 2, 3, 5, 7
 - result: 128
2 ^ 8:
 - path: 1, 2, 4, 8
 - result: 256
2 ^ 9:
 - path: 1, 2, 3, 6, 9
 - result: 512
2 ^ 10:
 - path: 1, 2, 3, 5, 10
 - result: 1024
2 ^ 11:
 - path: 1, 2, 3, 5, 10, 11
 - result: 2048
2 ^ 12:
 - path: 1, 2, 3, 6, 12
 - result: 4096
2 ^ 13:
 - path: 1, 2, 3, 5, 10, 13
 - result: 8192
2 ^ 14:
 - path: 1, 2, 3, 5, 7, 14
 - result: 16384
2 ^ 15:
 - path: 1, 2, 3, 5, 10, 15
 - result: 32768
2 ^ 16:
 - path: 1, 2, 4, 8, 16
 - result: 65536
2 ^ 17:
 - path: 1, 2, 4, 8, 16, 17
 - result: 131072
3 ^ 191:
 - path: 1, 2, 3, 5, 7, 14, 19, 38, 57, 95, 190, 191
 - result: 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
1.1 ^ 81:
 - path: 1, 2, 3, 5, 10, 20, 40, 41, 81
 - result: 2253.2402360440283
Translation of: Python
// version 1.1.3

import java.math.BigDecimal

var p = mutableMapOf(1 to 0)
var lvl = mutableListOf(listOf(1))

fun path(n: Int): List<Int> {
    if (n == 0) return emptyList<Int>()
    while (n !in p) {
        val q = mutableListOf<Int>()
        for (x in lvl[0]) {
            for (y in path(x)) { 
                if ((x + y) in p) break
                p[x + y] = x
                q.add(x + y)
            } 
        }
        lvl[0] = q
    }
    return path(p[n]!!) + n
}

fun treePow(x: Double, n: Int): BigDecimal {
    val r = mutableMapOf(0 to BigDecimal.ONE, 1 to BigDecimal(x.toString()))
    var p = 0
    for (i in path(n)) {
        r[i] = r[i - p]!! * r[p]!!
        p = i
    }
    return r[n]!!
}

fun showPow(x: Double, n: Int, isIntegral: Boolean = true) {
    println("$n: ${path(n)}")
    val f = if (isIntegral) "%.0f" else "%f"
    println("${f.format(x)} ^ $n = ${f.format(treePow(x, n))}\n")
} 

fun main(args: Array<String>) {
    for (n in 0..17) showPow(2.0, n)
    showPow(1.1, 81, false)
    showPow(3.0, 191)
}
Output:
0: []
2 ^ 0 = 1

1: [1]
2 ^ 1 = 2

2: [1, 2]
2 ^ 2 = 4

3: [1, 2, 3]
2 ^ 3 = 8

4: [1, 2, 4]
2 ^ 4 = 16

5: [1, 2, 4, 5]
2 ^ 5 = 32

6: [1, 2, 4, 6]
2 ^ 6 = 64

7: [1, 2, 4, 6, 7]
2 ^ 7 = 128

8: [1, 2, 4, 8]
2 ^ 8 = 256

9: [1, 2, 4, 8, 9]
2 ^ 9 = 512

10: [1, 2, 4, 8, 10]
2 ^ 10 = 1024

11: [1, 2, 4, 8, 10, 11]
2 ^ 11 = 2048

12: [1, 2, 4, 8, 12]
2 ^ 12 = 4096

13: [1, 2, 4, 8, 12, 13]
2 ^ 13 = 8192

14: [1, 2, 4, 8, 12, 14]
2 ^ 14 = 16384

15: [1, 2, 4, 8, 12, 14, 15]
2 ^ 15 = 32768

16: [1, 2, 4, 8, 16]
2 ^ 16 = 65536

17: [1, 2, 4, 8, 16, 17]
2 ^ 17 = 131072

81: [1, 2, 4, 8, 16, 32, 64, 80, 81]
1.100000 ^ 81 = 2253.240236

191: [1, 2, 4, 8, 16, 32, 64, 128, 160, 176, 184, 188, 190, 191]
3 ^ 191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
ClearAll[NextStep, TreePow]
NextStep[pows_List] := Module[{maxlen, sel, new, vals, knows},
  maxlen = Max[Length /@ pows[[All, "Path"]]];
  sel = Select[pows, Length[#["Path"]] == maxlen &];
  knows = pows[[All, "P"]];
  new = {};
  Do[
   vals = s["P"] + s["Path"];
   vals = DeleteCases[vals, Alternatives @@ Join[s["Path"], knows]];
   new = 
    Join[
     new, <|"Path" -> Append[s["Path"], #], "P" -> #|> & /@ vals];
   ,
   {s, sel}
   ];
  new //= DeleteDuplicatesBy[#["P"] &];
  SortBy[Join[pows, new], #["P"] &]
  ]
TreePow[path_List, base_] := Module[{db, tups},
  db = <|1 -> base|>;
  Do[
   tups = Tuples[Keys[db], 2];
   tups = Select[tups, #[[2]] >= #[[1]] &];
   tups = Select[tups, Total[#] == next &];
   If[Length[tups] < 1, Abort[]];
   tups //= First;
   AssociateTo[db, Total[tups] -> (Times @@ (db /@ tups))]
   ,
   {next, Rest[path]}
   ];
  db[Last[path]]
  ]

pows = {<|"Path" -> {1}, "P" -> 1|>};
steps = Nest[NextStep, pows, 7];
LayeredGraphPlot[DirectedEdge @@@ steps[[2 ;;, "Path", -2 ;;]], VertexLabels -> Automatic]

pows = {<|"Path" -> {1}, "P" -> 1|>};
steps = Nest[NextStep, pows, 5];
assoc = Association[#["P"] -> #["Path"] & /@ steps];
Dataset[assoc]
TreePow[assoc[#], 2] & /@ Range[1, 17]

pows = {<|"Path" -> {1}, "P" -> 1|>};
steps = NestWhile[NextStep, pows, Not[MemberQ[#[[All, "P"]], 191]] &];
SelectFirst[steps, #["P"] == 191 &]["Path"];
TreePow[%, 3]

pows = {<|"Path" -> {1}, "P" -> 1|>};
steps = NestWhile[NextStep, pows, Not[MemberQ[#[[All, "P"]], 81]] &];
SelectFirst[steps, #["P"] == 81 &]["Path"];
TreePow[%, 1.1]
Output:
[Graphics object showing the tree]

1	{1}
2	{1,2}
3	{1,2,3}
4	{1,2,4}
5	{1,2,3,5}
6	{1,2,3,6}
7	{1,2,3,5,7}
8	{1,2,4,8}
9	{1,2,3,6,9}
10	{1,2,3,5,10}
11	{1,2,3,6,9,11}
12	{1,2,3,6,12}
13	{1,2,3,5,10,13}
14	{1,2,3,5,7,14}
15	{1,2,3,6,9,15}
16	{1,2,4,8,16}
17	{1,2,4,8,16,17}
18	{1,2,3,6,9,18}
20	{1,2,3,5,10,20}
24	{1,2,3,6,12,24}
...	...

{2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072}

13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347

2253.24
Translation of: Kotlin
Library: bignum

This is a translation of the Kotlin/Python program. The algorithm is the same but there are some changes: replacement of global variables by a tree object, use of longer names, replacement of the "lvl" list of lists by a simple list, use of generics to handle the case of big integers...

import tables
import bignum

type

  Id = Natural    # Node identifier (= exponent value).

  Tree = object
    parents: Table[Id, Id]  # Mapping node id -> parent node id.
    lastLevel: seq[Id]      # List of node ids in current last level.


func initTree(): Tree =
  ## Return an initialized tree.
  const Root = Id(1)
  Tree(parents: {Root: Id(0)}.toTable, lastLevel: @[Root])


func path(tree: var Tree; id: Id): seq[Id] =
  ## Return the path to node with given id.

  if id == 0: return

  while id notin tree.parents:
    # Node "id" not yet present in the tree: build a new level.
    var newLevel: seq[Id]
    for x in tree.lastLevel:
      for y in tree.path(x):
        let newId = x + y
        if newId in tree.parents: break   # Node already created.
        # Create a new node.
        tree.parents[newId] = x
        newLevel.add newId
    tree.lastLevel = move(newLevel)

  # Node path is the concatenation of parent node path and node id.
  result = tree.path(tree.parents[id]) & id


func treePow[T: SomeNumber | Int](tree: var Tree; x: T; n: Natural): T =
  ## Compute x^n using the power tree.
  let one = when T is Int: newInt(1) else: T(1)
  var results = {0: one, 1: x}.toTable  # Intermediate and last results.
  var k = 0
  for i in tree.path(n):
    results[i] = results[i - k] * results[k]
    k = i
  return results[n]


proc showPow[T: SomeNumber | Int](tree: var Tree; x: T; n: Natural) =
  echo n, " → ", ($tree.path(n))[1..^1]
  let result = tree.treePow(x, n)
  echo x, "^", n, " = ", result


when isMainModule:

  var tree = initTree()
  for n in 0..17: tree.showPow(2, n)
  echo ""
  tree.showPow(1.1, 81)
  echo ""
  tree.showPow(newInt(3), 191)
Output:
0 → []
2^0 = 1
1 → [1]
2^1 = 2
2 → [1, 2]
2^2 = 4
3 → [1, 2, 3]
2^3 = 8
4 → [1, 2, 4]
2^4 = 16
5 → [1, 2, 4, 5]
2^5 = 32
6 → [1, 2, 4, 6]
2^6 = 64
7 → [1, 2, 4, 6, 7]
2^7 = 128
8 → [1, 2, 4, 8]
2^8 = 256
9 → [1, 2, 4, 8, 9]
2^9 = 512
10 → [1, 2, 4, 8, 10]
2^10 = 1024
11 → [1, 2, 4, 8, 10, 11]
2^11 = 2048
12 → [1, 2, 4, 8, 12]
2^12 = 4096
13 → [1, 2, 4, 8, 12, 13]
2^13 = 8192
14 → [1, 2, 4, 8, 12, 14]
2^14 = 16384
15 → [1, 2, 4, 8, 12, 14, 15]
2^15 = 32768
16 → [1, 2, 4, 8, 16]
2^16 = 65536
17 → [1, 2, 4, 8, 16, 17]
2^17 = 131072

81 → [1, 2, 4, 8, 16, 32, 64, 80, 81]
1.1^81 = 2253.240236044025

191 → [1, 2, 4, 8, 16, 32, 64, 128, 160, 176, 184, 188, 190, 191]
3^191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
Translation of: Kotlin
uses NumLibABC;

var
  p := Dict((1, 0));
  lvl := Lst(Lst(word(1)));

function tofraction(s: string): fraction;
begin
  var period := s.IndexOf('.');
  if period = -1 then result := Frc(s.ToBigInteger)
  else result := Frc(s.Remove(period, 1).ToBigInteger, Power(10bi, s.Length - period - 1));
end;

function path(n: word): List<word>;
begin
  result := new List<word>;
  if n = 0 then exit;
  while not p.ContainsKey(n) do
  begin
    var q := new List<word>;
    foreach var x in lvl[0] do
      foreach var y in path(x) do
      begin
        if (x + y) in p then break;
        p[x + y] := x;
        q.add(x + y);
      end;
    lvl[0] := q;
  end;
  result := path(p[n]) + Lst(n);
end;

function treePow(x: real; n: word): Fraction;
begin
  var frac := tofraction(FloatToStr(x));
  var r := Dict((0, Frc(1)), (1, frac));
  var p := 0;
  foreach var i in path(n) do
  begin
    r[i] := r[i - p] * r[p];
    p := i;
  end;
  result := r[n];
end;

procedure showPow(x: real; n: word);
begin
  writeln(n, ': ', path(n));
  writeln(x, '^', n, ' = ', treePow(x, n), #10);
end;

begin
  for var n := 0 to 17 do showPow(2, n);
  showPow(1.1, 81);
  showPow(3, 191);
end.
Output:
0: []
2^0 = 1

1: [1]
2^1 = 2

2: [1,2]
2^2 = 4

3: [1,2,3]
2^3 = 8

4: [1,2,4]
2^4 = 16

5: [1,2,4,5]
2^5 = 32

6: [1,2,4,6]
2^6 = 64

7: [1,2,4,6,7]
2^7 = 128

8: [1,2,4,8]
2^8 = 256

9: [1,2,4,8,9]
2^9 = 512

10: [1,2,4,8,10]
2^10 = 1024

11: [1,2,4,8,10,11]
2^11 = 2048

12: [1,2,4,8,12]
2^12 = 4096

13: [1,2,4,8,12,13]
2^13 = 8192

14: [1,2,4,8,12,14]
2^14 = 16384

15: [1,2,4,8,12,14,15]
2^15 = 32768

16: [1,2,4,8,16]
2^16 = 65536

17: [1,2,4,8,16,17]
2^17 = 131072

81: [1,2,4,8,16,32,64,80,81]
1.1^81 = 2253240236044012487937308538033349567966729852481170503814810577345406584190098644811/1000000000000000000000000000000000000000000000000000000000000000000000000000000000

191: [1,2,4,8,16,32,64,128,160,176,184,188,190,191]
3^191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
my @lvl = [1];
my %p = (1 => 0);

sub path {
    my ($n) = @_;
    return () if ($n == 0);
    until (exists $p{$n}) {
        my @q;
        foreach my $x (@{$lvl[0]}) {
            foreach my $y (path($x)) {
                my $z = $x + $y;
                last if exists($p{$z});
                $p{$z} = $x;
                push @q, $z;
            }
        }
        $lvl[0] = \@q;
    }
    (path($p{$n}), $n);
}

sub tree_pow {
    my ($x, $n) = @_;
    my %r = (0 => 1, 1 => $x);
    my $p = 0;
    foreach my $i (path($n)) {
        $r{$i} = $r{$i - $p} * $r{$p};
        $p = $i;
    }
    $r{$n};
}

sub show_pow {
    my ($x, $n) = @_;
    my $fmt = "%d: %s\n" . ("%g^%s = %f", "%s^%s = %s")[$x == int($x)] . "\n";
    printf($fmt, $n, "(" . join(" ", path($n)) . ")", $x, $n, tree_pow($x, $n));
}

show_pow(2, $_) for 0 .. 17;
show_pow(1.1, 81);
{
    use bigint (try => 'GMP');
    show_pow(3, 191);
}
Output:
0: ()
2^0 = 1
1: (1)
2^1 = 2
2: (1 2)
2^2 = 4
3: (1 2 3)
2^3 = 8
4: (1 2 4)
2^4 = 16
5: (1 2 4 5)
2^5 = 32
6: (1 2 4 6)
2^6 = 64
7: (1 2 4 6 7)
2^7 = 128
8: (1 2 4 8)
2^8 = 256
9: (1 2 4 8 9)
2^9 = 512
10: (1 2 4 8 10)
2^10 = 1024
11: (1 2 4 8 10 11)
2^11 = 2048
12: (1 2 4 8 12)
2^12 = 4096
13: (1 2 4 8 12 13)
2^13 = 8192
14: (1 2 4 8 12 14)
2^14 = 16384
15: (1 2 4 8 12 14 15)
2^15 = 32768
16: (1 2 4 8 16)
2^16 = 65536
17: (1 2 4 8 16 17)
2^17 = 131072
81: (1 2 4 8 16 32 64 80 81)
1.1^81 = 2253.240236
191: (1 2 4 8 16 32 64 128 160 176 184 188 190 191)
3^191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
Translation of: Go
Library: Phix/mpfr
with javascript_semantics
constant p = new_dict({{1,0}})
sequence lvl = {1}
 
function path(integer n)
    if n=0 then return {} end if
    while getd_index(n,p)=NULL do
        sequence q = {}
        for i=1 to length(lvl) do
            integer x = lvl[i]
            sequence px = path(x)
            for j=1 to length(px) do
                integer y = x+px[j]
                if getd_index(y,p)!=NULL then exit end if
                setd(y,x,p)
                q &= y
            end for
        end for
        lvl = q
    end while
    return path(getd(n,p))&n
end function
 
include mpfr.e
mpfr_set_default_precision(500)
 
function treepow(object x, integer n, sequence pn = {})
-- x can be atom or string (but not mpfr)
-- (asides: sequence r uses out-by-1 indexing, ie r[1] is for 0.
--          sequence c is used to double-check we are not trying
--          to use something which has not yet been calculated.)
    if pn={} then pn=path(n) end if
    sequence r = {mpfr_init(1),mpfr_init(x)},
             c = {1,1}&repeat(0,max(0,n-1))
    for i=1 to max(0,n-1) do r &= mpfr_init() end for
    integer p = 0
    for i=1 to length(pn) do
        integer pi = pn[i]
        if c[pi-p+1]=0 then ?9/0 end if
        if c[p+1]=0 then ?9/0 end if
        mpfr_mul(r[pi+1],r[pi-p+1],r[p+1])
        c[pi+1] = 1
        p = pi
    end for
--  string res = shorten(trim_tail(mpfr_sprintf("%.83Rf",r[n+1]),".0"))
    string res = shorten(trim_tail(mpfr_get_fixed(r[n+1],83),".0"))
    r = mpfr_free(r)
    return res
end function
 
procedure showpow(object x, integer n)
    sequence pn = path(n)
    string xs = iff(string(x)?x:sprintf("%3g",x))
    printf(1,"%48v : %3s ^ %d = %s\n", {pn,xs,n,treepow(x,n,pn)})
end procedure
 
for n=0 to 17 do
    showpow(2,n)
end for
showpow("1.1",81)
showpow(3,191)
Output:
                                              {} :   2 ^ 0 = 1
                                             {1} :   2 ^ 1 = 2
                                           {1,2} :   2 ^ 2 = 4
                                         {1,2,3} :   2 ^ 3 = 8
                                         {1,2,4} :   2 ^ 4 = 16
                                       {1,2,4,5} :   2 ^ 5 = 32
                                       {1,2,4,6} :   2 ^ 6 = 64
                                     {1,2,4,6,7} :   2 ^ 7 = 128
                                       {1,2,4,8} :   2 ^ 8 = 256
                                     {1,2,4,8,9} :   2 ^ 9 = 512
                                    {1,2,4,8,10} :   2 ^ 10 = 1024
                                 {1,2,4,8,10,11} :   2 ^ 11 = 2048
                                    {1,2,4,8,12} :   2 ^ 12 = 4096
                                 {1,2,4,8,12,13} :   2 ^ 13 = 8192
                                 {1,2,4,8,12,14} :   2 ^ 14 = 16384
                              {1,2,4,8,12,14,15} :   2 ^ 15 = 32768
                                    {1,2,4,8,16} :   2 ^ 16 = 65536
                                 {1,2,4,8,16,17} :   2 ^ 17 = 131072
                        {1,2,4,8,16,32,64,80,81} : 1.1 ^ 81 = 2253.240236044012487937308538033349567966729852481170503814810577345406584190098644811
  {1,2,4,8,16,32,64,128,160,176,184,188,190,191} :   3 ^ 191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
from __future__ import print_function

# remember the tree generation state and expand on demand
def path(n, p = {1:0}, lvl=[[1]]):
	if not n: return []
	while n not in p:
		q = []
		for x,y in ((x, x+y) for x in lvl[0] for y in path(x) if not x+y in p):
			p[y] = x
			q.append(y)
		lvl[0] = q

	return path(p[n]) + [n]

def tree_pow(x, n):
    r, p = {0:1, 1:x}, 0
    for i in path(n):
        r[i] = r[i-p] * r[p]
        p = i
    return r[n]

def show_pow(x, n):
    fmt = "%d: %s\n" + ["%g^%d = %f", "%d^%d = %d"][x==int(x)] + "\n"
    print(fmt % (n, repr(path(n)), x, n, tree_pow(x, n)))

for x in range(18): show_pow(2, x)
show_pow(3, 191)
show_pow(1.1, 81)
Output:
0: []
2^0 = 1

1: [1]
2^1 = 2

2: [1, 2]
2^2 = 4

<... snipped ...>

17: [1, 2, 4, 8, 16, 17]
2^17 = 131072

191: [1, 2, 3, 5, 7, 14, 19, 38, 57, 95, 190, 191]
3^191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347

81: [1, 2, 3, 5, 10, 20, 40, 41, 81]
1.1^81 = 2253.240236

Using the mpmath library

Translation of: Go
""" https://rosettacode.org/wiki/Knuth%27s_power_tree """

from typing import List, Dict
from mpmath import mp

# Set decimal precision for mpmath calculations (like Go example 320 bits)
mp.dps = 140

# Global variables
p: Dict[int, int] = {1: 0}
lvl: List[List[int]] = [[1]]


def path(n: int) -> List[int]:
    """ return path to the node with id ''n'' """
    if n == 0:
        return []

    while n not in p:
        q: List[int] = []
        for x in lvl[0]:
            for y in path(x):
                z = x + y
                if z in p:
                    break
                p[z] = x
                q.append(z)
        lvl[0] = q

    r = path(p[n]) + [n]
    return r


def tree_pow(x: float, n: int) -> mp.mpf:
    """ use power tree to compute x ** n """
    r: Dict[int, mp.mpf] = {0: mp.mpf('1'), 1: mp.mpf(str(x))}
    prev = 0
    for i in path(n):
        r[i] = mp.mpf(r[i - prev] * r[prev])
        prev = i
    return r[n]


def show_pow(x: float, n: int) -> None:
    """ print the power calculation """
    print(f"{n}: {path(n)}")
    y = tree_pow(x, n)
    ans = mp.nstr(y, n=100, strip_zeros=True)[
        :-2] if mp.isint(y) else mp.nstr(y, n=10)
    print(f"{mp.nstr(x)} ^ {n} = {ans}\n")


if __name__ == "__main__":
    for expo in range(18):
        show_pow(2, expo)
    show_pow(1.1, 81)
    show_pow(3.0, 191)
Output:
0: []
2 ^ 0 = 1

1: [1]
2 ^ 1 = 2

2: [1, 2]
2 ^ 2 = 4

3: [1, 2, 3]
2 ^ 3 = 8

4: [1, 2, 4]
2 ^ 4 = 16

5: [1, 2, 4, 5]
2 ^ 5 = 32

6: [1, 2, 4, 6]
2 ^ 6 = 64

7: [1, 2, 4, 6, 7]
2 ^ 7 = 128

8: [1, 2, 4, 8]
2 ^ 8 = 256

9: [1, 2, 4, 8, 9]
2 ^ 9 = 512

10: [1, 2, 4, 8, 10]
2 ^ 10 = 1024

11: [1, 2, 4, 8, 10, 11]
2 ^ 11 = 2048

12: [1, 2, 4, 8, 12]
2 ^ 12 = 4096

13: [1, 2, 4, 8, 12, 13]
2 ^ 13 = 8192

14: [1, 2, 4, 8, 12, 14]
2 ^ 14 = 16384

15: [1, 2, 4, 8, 12, 14, 15]
2 ^ 15 = 32768

16: [1, 2, 4, 8, 16]
2 ^ 16 = 65536

17: [1, 2, 4, 8, 16, 17]
2 ^ 17 = 131072

81: [1, 2, 4, 8, 16, 32, 64, 80, 81]
1.1 ^ 81 = 2253.240236

191: [1, 2, 4, 8, 16, 32, 64, 128, 160, 176, 184, 188, 190, 191]
3.0 ^ 191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347

Translation of: Python
#lang racket

(define pow-path-cache (make-hash '((0 . (0)) (1 . (0 1)))))

(define pow-path-level '(1))  

(define (pow-path-extend!)
  (define next-level
    (for*/fold ([next-level '()])
               ([x (in-list pow-path-level)]
                [y (in-list (pow-path x))]
                [s (in-value (+ x y))]
                #:when (not (hash-has-key? pow-path-cache s)))
      (hash-set! pow-path-cache s (append (hash-ref pow-path-cache x) (list s)))
      (cons s next-level)))
  (set! pow-path-level (reverse next-level)))

(define (pow-path n)
  (let loop ()
    (unless (hash-has-key? pow-path-cache n)
      (pow-path-extend!)
      (loop)))
 (hash-ref pow-path-cache n))
 
(define (pow-tree x n)
  (define pows (make-hash `((0 . 1) (1 . ,x))))
  (for/fold ([prev 0])
            ([i (in-list (pow-path n))])
    (hash-set! pows i (* (hash-ref pows (- i prev)) (hash-ref pows prev)))
    i)
  (hash-ref pows n))
 
(define (show-pow x n)
  (printf "~a: ~a\n" n (cdr (pow-path n)))
  (printf "~a^~a = ~a\n" x n (pow-tree x n)))
 
(for ([x (in-range 18)])
  (show-pow 2 x))
(show-pow 3 191)
(show-pow 1.1 81)
Output:
0: ()
2^0 = 1
1: (1)
2^1 = 2
2: (1 2)
2^2 = 4
3: (1 2 3)
2^3 = 8
4: (1 2 4)
2^4 = 16
5: (1 2 3 5)
2^5 = 32
6: (1 2 3 6)
2^6 = 64
7: (1 2 3 5 7)
2^7 = 128
8: (1 2 4 8)
2^8 = 256
9: (1 2 3 6 9)
2^9 = 512
10: (1 2 3 5 10)
2^10 = 1024
11: (1 2 3 5 10 11)
2^11 = 2048
12: (1 2 3 6 12)
2^12 = 4096
13: (1 2 3 5 10 13)
2^13 = 8192
14: (1 2 3 5 7 14)
2^14 = 16384
15: (1 2 3 5 10 15)
2^15 = 32768
16: (1 2 4 8 16)
2^16 = 65536
17: (1 2 4 8 16 17)
2^17 = 131072
191: (1 2 3 5 7 14 19 38 57 95 190 191)
3^191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
81: (1 2 3 5 10 20 40 41 81)
1.1^81 = 2253.2402360440283



(formerly Perl 6) Paths are random. It is possible replace .pick(*) with .reverse if you want paths as in Perl, or remove it for Python paths.

use v6;

sub power-path ($n ) {
    state @unused_nodes = (2,);
    state @power-tree = (False,0,1);
    
    until @power-tree[$n].defined {
        my $node = @unused_nodes.shift;

        for  $node X+ power-path($node).pick(*) {
            next if @power-tree[$_].defined;
            @unused_nodes.push($_);
            @power-tree[$_]= $node;
        }        
    }

    ( $n, { @power-tree[$_] } ...^ 0 ).reverse;
}

multi power ( $, 0 ) { 1 };
multi power ( $n, $exponent ) {
    state  %p;
    my     %r =  %p{$n}  // ( 0 => 1, 1 => $n ) ;  

    for power-path( $exponent ).rotor( 2 => -1 ) -> ( $p, $c ) {
        %r{ $c } = %r{ $p } * %r{ $c - $p }
    }

    %p{$n} := %r ;
    %r{ $exponent }
}

say 'Power paths: ',      pairs map *.&power-path,    ^18;
say '2 ** key = value: ', pairs map { 2.&power($_) }, ^18; 

say 'Path for 191: ', power-path 191;
say '3 ** 191 = ',    power   3, 191;
say 'Path for 81: ',  power-path  81;
say '1.1 ** 81 = ',   power 1.1,  81;
Output:
Power paths: (0 => () 1 => (1) 2 => (1 2) 3 => (1 2 3) 4 => (1 2 4) 5 => (1 2 3 5) 6 => (1 2 3 6) 7 => (1 2 3 6 7) 8 => (1 2 4 8) 9 => (1 2 3 6 9) 10 => (1 2 3 5 10) 11 => (1 2 3 6 9 11) 12 => (1 2 3 6 12) 13 => (1 2 3 6 12 13) 14 => (1 2 3 6 12 14) 15 => (1 2 3 6 9 15) 16 => (1 2 4 8 16) 17 => (1 2 4 8 16 17))
2 ** key = value: (0 => 1 1 => 2 2 => 4 3 => 8 4 => 16 5 => 32 6 => 64 7 => 128 8 => 256 9 => 512 10 => 1024 11 => 2048 12 => 4096 13 => 8192 14 => 16384 15 => 32768 16 => 65536 17 => 131072)
Path for 191: (1 2 3 6 9 18 27 54 108 162 189 191)
3 ** 191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
Path for 81: (1 2 3 6 9 18 27 54 81)
1.1 ** 81 = 2253.24023604401

This REXX version supports results up to 1,000 decimal digits   (which can be expanded with the   numeric digits nnn   REXX statement.

Also, negative powers are supported.

/*REXX program produces & displays a  power tree  for P,  and calculates & displays X^P.*/
numeric digits 1000                              /*be able to handle some large numbers.*/
parse arg XP                                     /*get sets:   X, low power, high power.*/
if XP=''  then XP='2 -4 17   3 191 191   1.1 81' /*Not specified?  Then use the default.*/
          /*────── X LP HP   X  LP  HP    X  LP  ◄── X, low power, high power ··· repeat*/
     do  until XP=''
     parse var XP    x pL pH   XP;    x= x / 1   /*get X, lowP, highP; and normalize X. */
     if pH=''  then pH= pL                       /*No highPower?  Then assume lowPower. */

       do e=pL  to pH;           p= abs(e) / 1   /*use a range of powers;   use  │E│    */
       $= powerTree(p);          w= length(pH)   /*construct the power tree, (pow list).*/
                                                 /* [↑]  W≡length for an aligned display*/
          do i=1  for words($);  @.i= word($, i) /*build a fast Knuth's power tree array*/
          end   /*i*/

       if p==0  then do;  z= 1;  call show;  iterate;  end  /*handle case of zero power.*/
       !.= .;   z= x;     !.1= z;     prv= z     /*define/construct the first power of X*/

           do k=2  to words($);       n= @.k     /*obtain the power (number) to be used.*/
           prev= k - 1;     diff= n - @.prev     /*these are used for the odd powers.   */
           if n//2==0  then z= prv ** 2          /*Even power?   Then square the number.*/
                       else z= z * !.diff        /* Odd   "        "  mult. by pow diff.*/
           !.n= z                                /*remember for other multiplications.  */
           prv= z                                /*remember for squaring the numbers.   */
           end   /*k*/
       call show                                 /*display the expression and its value.*/
       end       /*e*/
     end         /*until XP ···*/
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
powerTree: arg y 1 oy;   $=                      /*Z is the result; $ is the power tree.*/
           if y=0 | y=1  then return y           /*handle special cases for zero & unity*/
           #.= 0;   @.= 0;    #.0= 1             /*define default & initial array values*/
                                                 /* [↓]  add blank "flag" thingy──►list.*/
                   do  while \(y//2);  $= $ ' '  /*reduce "front" even power #s to odd #*/
                   if y\==oy  then $= y $        /*(only)  ignore the first power number*/
                   y= y % 2                      /*integer divide the power (it's even).*/
                   end   /*while*/

           if $\==''  then $= y $                /*re─introduce the last power number.  */
           $= $ oy                               /*insert last power number 1st in list.*/
           if y>1  then do      while  @.y==0;            n= #.0;        m= 0
                          do    while  n\==0;             q= 0;          s= n
                            do  while  s\==0;             _= n + s
                            if @._==0  then do;  if q==0  then m_= _;
                                                 #._= q;  @._= n;        q= _
                                            end
                            s= @.s
                            end   /*while s¬==0*/
                          if q\==0  then do;   #.m= q;   m= m_;   end
                          n= #.n
                          end     /*while n¬==0*/
                        #.m= 0
                        end       /*while @.y==0*/
           z= @.y
                            do  while z\==0;   $= z $;   z= @.z;  end /*build power list*/
           return space($)                                            /*del extra blanks*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: if e<0  then z=format(1/z, , 40)/1;     _=right(e, w)           /*use reciprocal? */
      say left('power tree for '  _  " is: "  $,60)  '═══'  x"^"_  ' is: '  z;      return
output   when using the default inputs:
power tree for  -4  is:  1 2 4                               ═══ 2^-4  is:  0.0625
power tree for  -3  is:  1 2 3                               ═══ 2^-3  is:  0.125
power tree for  -2  is:  1 2                                 ═══ 2^-2  is:  0.25
power tree for  -1  is:  1                                   ═══ 2^-1  is:  0.5
power tree for   0  is:  0                                   ═══ 2^ 0  is:  1
power tree for   1  is:  1                                   ═══ 2^ 1  is:  2
power tree for   2  is:  1 2                                 ═══ 2^ 2  is:  4
power tree for   3  is:  1 2 3                               ═══ 2^ 3  is:  8
power tree for   4  is:  1 2 4                               ═══ 2^ 4  is:  16
power tree for   5  is:  1 2 3 5                             ═══ 2^ 5  is:  32
power tree for   6  is:  1 2 3 6                             ═══ 2^ 6  is:  64
power tree for   7  is:  1 2 3 5 7                           ═══ 2^ 7  is:  128
power tree for   8  is:  1 2 4 8                             ═══ 2^ 8  is:  256
power tree for   9  is:  1 2 3 6 9                           ═══ 2^ 9  is:  512
power tree for  10  is:  1 2 3 5 10                          ═══ 2^10  is:  1024
power tree for  11  is:  1 2 3 5 10 11                       ═══ 2^11  is:  2048
power tree for  12  is:  1 2 3 6 12                          ═══ 2^12  is:  4096
power tree for  13  is:  1 2 3 5 10 13                       ═══ 2^13  is:  8192
power tree for  14  is:  1 2 3 5 7 14                        ═══ 2^14  is:  16384
power tree for  15  is:  1 2 3 5 10 15                       ═══ 2^15  is:  32768
power tree for  16  is:  1 2 4 8 16                          ═══ 2^16  is:  65536
power tree for  17  is:  1 2 4 8 16 17                       ═══ 2^17  is:  131072
power tree for  191  is:  1 2 3 5 7 14 19 38 57 95 190 191   ═══ 3^191  is:  13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
power tree for  81  is:  1 2 3 5 10 20 40 41 81              ═══ 1.1^81  is:  2253.240236044012487937308538033349567966729852481170503814810577345406584190098644811
Translation of: zkl
var lvl = [[1]]
var p = Hash(1 => 0)

func path(n) is cached {
    n || return []
    while (n !~ p) {
        var q = []
        for x in lvl[0] {
            for y in path(x) {
                break if (x+y ~~ p)
                y = x+y
                p{y} = x
                q << y
            }
        }
        lvl[0] = q
    }
    path(p{n}) + [n]
}

func tree_pow(x, n) {
    var r = Hash(0 => 1, 1 => x)
    var p = 0
    for i in path(n) {
        r{i} = (r{i-p} * r{p})
        p = i
    }
    r{n}
}

func show_pow(x, n) {
    var fmt = ("%d: %s\n" + ["%g^%s = %f", "%s^%s = %s"][x.is_int] + "\n")
    print(fmt % (n, path(n), x, n, tree_pow(x, n)))
}

for x in ^18 { show_pow(2, x) }
show_pow(1.1, 81)
show_pow(3, 191)
Output:
0: []
2^0 = 1
1: [1]
2^1 = 2
2: [1, 2]
2^2 = 4
3: [1, 2, 3]
2^3 = 8
4: [1, 2, 4]
2^4 = 16
5: [1, 2, 4, 5]
2^5 = 32
6: [1, 2, 4, 6]
2^6 = 64
7: [1, 2, 4, 6, 7]
2^7 = 128
8: [1, 2, 4, 8]
2^8 = 256
9: [1, 2, 4, 8, 9]
2^9 = 512
10: [1, 2, 4, 8, 10]
2^10 = 1024
11: [1, 2, 4, 8, 10, 11]
2^11 = 2048
12: [1, 2, 4, 8, 12]
2^12 = 4096
13: [1, 2, 4, 8, 12, 13]
2^13 = 8192
14: [1, 2, 4, 8, 12, 14]
2^14 = 16384
15: [1, 2, 4, 8, 12, 14, 15]
2^15 = 32768
16: [1, 2, 4, 8, 16]
2^16 = 65536
17: [1, 2, 4, 8, 16, 17]
2^17 = 131072
81: [1, 2, 4, 8, 16, 32, 64, 80, 81]
1.1^81 = 2253.240236
191: [1, 2, 4, 8, 16, 32, 64, 128, 160, 176, 184, 188, 190, 191]
3^191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
Translation of: Kotlin
Library: Wren-big
Library: Wren-fmt
import "./big" for BigRat
import "./fmt" for Fmt

var p = { 1: 0 }
var lvl = [[1]]

var path // recursive
path = Fn.new { |n|
    if (n == 0) return []
    while (!p.containsKey(n)) {
        var q = []
        for (x in lvl[0]) {
            System.write("") // guard against VM recursion bug
            for (y in path.call(x)) {
                if (p.containsKey(x + y)) break
                p[x + y] = x
                q.add(x + y)
            }
        }
        lvl[0] = q
    }
    System.write("") // guard against VM recursion bug
    var l = path.call(p[n])
    l.add(n)
    return l
}

var treePow = Fn.new { |x, n|
    var r = { 0: BigRat.one, 1: BigRat.fromDecimal(x) }
    var p = 0
    for (i in path.call(n)) {
        r[i] = r[i-p] * r[p]
        p = i
    }
    return r[n]
}

var showPow = Fn.new { |x, n|
    System.print("%(n): %(path.call(n))")
    Fmt.print("$s ^ $d = $s\n", x, n, treePow.call(x, n).toDecimal(6))
}

for (n in 0..17) showPow.call(2, n)
showPow.call(1.1, 81)
showPow.call(3, 191)
Output:
0: []
2 ^ 0 = 1

1: [1]
2 ^ 1 = 2

2: [1, 2]
2 ^ 2 = 4

3: [1, 2, 3]
2 ^ 3 = 8

4: [1, 2, 4]
2 ^ 4 = 16

5: [1, 2, 4, 5]
2 ^ 5 = 32

6: [1, 2, 4, 6]
2 ^ 6 = 64

7: [1, 2, 4, 6, 7]
2 ^ 7 = 128

8: [1, 2, 4, 8]
2 ^ 8 = 256

9: [1, 2, 4, 8, 9]
2 ^ 9 = 512

10: [1, 2, 4, 8, 10]
2 ^ 10 = 1024

11: [1, 2, 4, 8, 10, 11]
2 ^ 11 = 2048

12: [1, 2, 4, 8, 12]
2 ^ 12 = 4096

13: [1, 2, 4, 8, 12, 13]
2 ^ 13 = 8192

14: [1, 2, 4, 8, 12, 14]
2 ^ 14 = 16384

15: [1, 2, 4, 8, 12, 14, 15]
2 ^ 15 = 32768

16: [1, 2, 4, 8, 16]
2 ^ 16 = 65536

17: [1, 2, 4, 8, 16, 17]
2 ^ 17 = 131072

81: [1, 2, 4, 8, 16, 32, 64, 80, 81]
1.1 ^ 81 = 2253.240236

191: [1, 2, 4, 8, 16, 32, 64, 128, 160, 176, 184, 188, 190, 191]
3 ^ 191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
Translation of: Python
# remember the tree generation state and expand on demand
fcn path(n,p=Dictionary(1,0),lvl=List(List(1))){
   if(n==0) return(T);
   while(not p.holds(n)){
      q:=List();
      foreach x,y in (lvl[0],path(x,p,lvl)){
         if(p.holds(x+y)) break;  // not this y
	 y=x+y; p[y]=x;
	 q.append(y);
      }
      lvl[0]=q
   }
   path(p[n],p,lvl) + n
}

fcn tree_pow(x,n,path){
   r,p:=Dictionary(0,1, 1,x), 0;
   foreach i in (path){ r[i]=r[i-p]*r[p]; p=i; }
   r[n]
}
 
fcn show_pow(x,n){
   fmt:="%d: %s\n" + T("%g^%d = %f", "%d^%d = %d")[x==Int(x)] + "\n";
   println(fmt.fmt(n,p:=path(n),x,n,tree_pow(x,n,p)))
}
foreach x in (18){ show_pow(2,x) }
show_pow(1.1,81);

var [const] BN=Import("zklBigNum");  // GNU GMP big ints
show_pow(BN(3),191);
Output:
0: L()
2^0 = 1

1: L(1)
2^1 = 2

2: L(1,2)
2^2 = 4

3: L(1,2,3)
2^3 = 8

4: L(1,2,4)
2^4 = 16

5: L(1,2,4,5)
2^5 = 32

6: L(1,2,4,6)
2^6 = 64

7: L(1,2,4,6,7)
2^7 = 128

8: L(1,2,4,8)
2^8 = 256

9: L(1,2,4,8,9)
2^9 = 512

10: L(1,2,4,8,10)
2^10 = 1024

11: L(1,2,4,8,10,11)
2^11 = 2048

12: L(1,2,4,8,12)
2^12 = 4096

13: L(1,2,4,8,12,13)
2^13 = 8192

14: L(1,2,4,8,12,14)
2^14 = 16384

15: L(1,2,4,8,12,14,15)
2^15 = 32768

16: L(1,2,4,8,16)
2^16 = 65536

17: L(1,2,4,8,16,17)
2^17 = 131072

81: L(1,2,4,8,16,32,64,80,81)
1.1^81 = 2253.240236

191: L(1,2,4,8,16,32,64,128,160,176,184,188,190,191)
3^191 = 13494588674281093803728157396523884917402502294030101914066705367021922008906273586058258347
Cookies help us deliver our services. By using our services, you agree to our use of cookies.
Knuth's power tree

Morty Proxy This is a proxified and sanitized view of the page, visit original site.