Find the powertrain!

29

The winner (pretty obviously) is Dennis ♦, who used Jelly with 10 bytes!

This challenge will still be up here, however results won't be taken anymore.


The powertrain of a number is a concept by John Conway (who is also notable for making Conway's Game of Life, but that's not the point). It is defined as so:

For any number enter image description here..., the powertrain of the number is enter image description here... (i.e. every 2nd digit, from left to right, is a power of the digit before that). This process is repeated until the result is a single digit.

EXAMPLES:

2592 => (2^5)(9^2) = 2592 <= Cannot be further decomposed 135 => (1^3)5 = 5 1234 => (1^2)(3^4) = 81 => (8^1) = 8 1100 => (1^1)(0^0) = 1 # (0^0) = 1 -42 => -42 # Negative numbers output the input

Your challenge is, for any number n in the input, return powertrain(n) (i.e. n after the powertrain decomposition is finished) as output.

This is code golf, so shortest amount of bytes wins.

DISCLAIMER-THINGS:

  • You can have an odd number of digits in the input, the last digit just won't have a power.
  • 0^0 is 1, because if it was 0, then a lot of numbers would instantly collapse to 0 or 1.
  • If the number is indestructible in any part of the computation process (e.g. if it ends up with 2592), then you can just output the number.
  • If the input is < 10 (i.e. all single digit numbers and negatives), output the input.

I'll probably announce a winner after a few hours days.

Current leaderboard:

  1. Jelly (Dennis ♦): 10
  2. Pyth (DenkerAffe): 16
  3. MATL (Don Muesli): 21
  4. Perl (Ton Hospel): 42
  5. Haskell (Damien): 64
  6. Javascript ES6 (edc65): 71
  7. Mathematica (murphy): 74
  8. Mathematica (LegionMammal978) and Haskell (Renzeee): 77
  9. Python 2 (mathmandan): 111
  10. Python 3 (Erwan): 161
  11. Java 8 (Blue): 229
  12. Oracle SQL 11.2 (Jeto): 456
  13. Befunge '93 (Lex): 490

clismique

Posted 2016-03-08T07:23:23.937

Reputation: 6 600

Some more test cases would be appreciated. – Mego – 2016-03-08T07:34:09.837

So the input will have 4 digits max? – Denker – 2016-03-08T07:42:08.383

@DenkerAffe No, there is no bound to the digits. They can be as long as you want. The examples were just for simplicity (because I can't be bothered to work out really long ones). – clismique – 2016-03-08T07:42:59.913

7What if a cycle is reached, but the period of the cycle is not 1, or the input number is not part of the cycle? – feersum – 2016-03-08T07:44:15.710

You can output the repeating number. For loops of numbers, I'm certain there aren't any within the realms of feasibility, so you can output whatever, really. Also, it's left to right - I am such an idiot, it's actually not funny. – clismique – 2016-03-08T07:55:22.743

1"I'm certain there aren't any within the realms of feasibility". Can we assume it will never happen? I.e. allowing the loop to go on forever if a cycle of period > 1 is reached? – Stewie Griffin – 2016-03-08T08:01:03.277

@StewieGriffin There haven't been any found so far. Then again, Google gives results of motor vehicles when I search up "powertrain", so... you can assume it never happens. – clismique – 2016-03-08T08:02:45.743

6Proposed test cases: 1100 and -42 It's easy to miss rules about edge cases if the do not show up in the test cases. – Dennis – 2016-03-08T13:24:29.653

What exactly is powertrain(n)? Is it a number, a list of numbers, or a sequence of computations? The output format is unclear from the spec. – Zgarb – 2016-03-08T15:31:11.737

@Zgarb It's just the number going through the powertrain. I couldn't think of a better way to describe it, but it's not a function or anything. – clismique – 2016-03-09T01:21:52.863

24547284284866560000000000 also has a period of 1. – Ian Miller – 2016-03-09T13:07:15.007

But 24547284284866560000000000 is so unfeasibly large that no language has the capacity to do that (also, that is why I put the 0^0 = 1 rule, coincidentally). – clismique – 2016-03-10T09:58:40.323

Answers

4

Jelly, 15 14 12 10 bytes

Ds2*/€Pµ³¡

Try it online!

How it works

Ds2*/€Pµ³¡  Main link. Argument: n

D           Convert n into the array of its decimal digits.
 s2         Split into pairs of digits.
   */€      Reduce each pair by exponentiation.
      P     Take the product of the resulting powers.
       µ    Push the preceding chain as a link, and start a new one.
        ³¡  Execute the link n times and return the last result.

Dennis

Posted 2016-03-08T07:23:23.937

Reputation: 196 637

This could be made shorter by simply iterating n times, but I don't have a proof that it works for all possible inputs. – Dennis – 2016-03-08T13:55:07.193

1

You should be ok for any reasonable number. In fact you are almost certainly ok for *ANY* number using 16 iterations: https://oeis.org/A133503

– Ton Hospel – 2016-03-08T14:22:50.017

@Dennis Hm, that's what I do in my answer – Luis Mendo – 2016-03-08T14:50:46.910

1@DonMuesli And now that I've thought about it, it probably works. The odds of getting a 0 and an odd index are overwhelming... – Dennis – 2016-03-08T16:22:34.363

In modern Jelly, this could be done in 7 bytes: D*2/Pµ¡

– Dennis – 2017-03-31T01:29:25.633

5

Haskell, 67 64 bytes

(>>=(==))>>=until$p.show is an unnamed function taking an integer as input and returning its powertrain.

Saved 3 bytes thanks to Zgarb

p(x:y:r)=p[x]^p[y]*p r;p[]=1;p x=read x
(>>=(==))>>=until$p.show

Damien

Posted 2016-03-08T07:23:23.937

Reputation: 2 407

1((==)=<<g) saves two bytes over (\n->g n==n). – Zgarb – 2016-03-08T15:58:04.250

Wow, I'm not familiar with the ((->) r) instance of Monad. Thanks for the trick. – Damien – 2016-03-08T16:36:38.433

This barrage of punctuation marks (>>=(==))>>= really looks like a train! – Andreï Kostyrka – 2016-08-31T10:06:10.970

4

Perl, 42 48 bytes

Include +2 for -lp (you can drop the -l too but I like newlines)

Run with input on STDIN, e.g.

perl -lp powertrain.pl <<< 1234

powertrain.pl:

s/\B/1&pos?"**":"*"/eg until++$.>($_=eval)

(on older perls you can also drop the space between the regex and until)

This won't be able to handle the fixed point 24547284284866560000000000 but that large a value won't work anyways because by that time perl switched to exponential notation.

The above version is will in fact work fast (at most 2592 loops) for all numbers that perl can represent without using exponential notation since it is proven that there are no fixed points between 2592 and 24547284284866560000000000 (https://oeis.org/A135385)

This does however assume something as yet unproven. In principle there could be a reduction that takes more than X=10^7 steps (it is conjectured that no non-fixed point takes more than 16 steps, https://oeis.org/A133503) whose value dips below X (but above 10^7) and then goes up again. If that is the case I must fall back to:

s/\B/1&pos?"**":"*"/eg until$s{$_=eval}++||/-/

Explanation

The code works by putting ** and * (alternating) between the digits

s/\B/1&pos?"**":"*"/eg

so 2592 becomes 2**5*9**2 and 12345 becomes 1**2*3**4*5. These are valid perl expressions that can be evaluated with

$_ = eval

(0**0 is 1 in perl). Then just put a loop around that with a counter that makes it expire. Since except for the fixed points the values go down extremely quickly the powertrain series converges before the counter gets a chance to really get going

Ton Hospel

Posted 2016-03-08T07:23:23.937

Reputation: 14 114

3

Pyth, 25 18 11 16 bytes

?<Q0Qu*F^McjGT2Q

Try it here!

7 14 bytes saved with help from @Jakube

Explanation

?<Q0Qu*F^McjGT2Q   # Q = eval(input)

?<Q0Q              # If input is negative return Q
     u         Q   # apply the following function until we reach a cycle               
                   # starting value is Q and the current value is in G
           jGT     # split input into a list of digits
          c   2    # split into pairs of 2
        ^M         # compute the power for every pair
      *F           # compute the product of all powers

Denker

Posted 2016-03-08T07:23:23.937

Reputation: 6 639

1Is Pyth basically just a golfed version of Python, except with minor changes? – clismique – 2016-03-08T09:09:22.193

1@Jakube Thanks for the hints! :) Still early in the morning for me... – Denker – 2016-03-08T09:20:14.687

@DerpfacePython Yea, kinda. Have a look at the docs if you wanna learn about it.

– Denker – 2016-03-08T09:21:26.520

No problem. ;-) – Jakube – 2016-03-08T09:35:11.283

This looks buggy for cases where the input is negative. – Peter Taylor – 2016-03-08T10:57:08.257

@PeterTaylor Fixed! – Denker – 2016-03-08T11:03:46.723

4@DerpfacePython Pyth started out as just "shortened Python", but to call it that now would be disingenuous. Pyth has significantly diverged from Python. – Mego – 2016-03-08T17:33:11.110

3

Python 2, 111 bytes

def p(n,b=0,o=''):
 if n<1:return n
 for c in str(n):o+=c+'**'[b:];b=~b
 j=eval(o+'1');return p(j)if j-n else j

The idea is to make a string where the digits of n are separated by operations which alternate between * and **, and then eval that string. (Other solutions use this same idea; see for example Ton Hospel's Perl answer.)

So, the operation switches back and forth between '**'[0:], which is **, and '**'[-1:], which is just *.

However, by the end of the for-loop, the string ends with an operation (one or the other), so we either need to drop the last operation, or else add another digit, in order for the string to make sense.

Fortunately, appending a 1 on the end will work no matter which operation is last. (If you like, 1 is a one-sided identity from the right, for both multiplication and exponentiation. Another way of saying this is that powertrain(n) == powertrain(10*n + 1) for all n>0.)

Finally, if the result of the eval happens to be the same as the input (as in a length-1 cycle), the function terminates. Otherwise, the function calls itself on the result. (It will hang forever on any cycle of length > 1, but according to the OP's comments I am allowed to assume there are no such cycles.)

(Note: the above explanation works for single-digit positive integers, since a single-digit input n will be completed to n**1 which will result in a 1-cycle. However, we also need to accept non-positive input, so there's a condition at the beginning that short-circuits if the input is less than 1. We could eliminate that line, and save 17 bytes, if the input were guaranteed to be non-negative.)

mathmandan

Posted 2016-03-08T07:23:23.937

Reputation: 943

This sounds biased, but... upvote for being Python 2. And it has an explanation. – clismique – 2016-03-09T01:52:00.633

@DerpfacePython Thanks! (I guess this would work just as well in Python 3...) – mathmandan – 2016-03-09T02:18:07.443

3

Java 8, 265 244 229 bytes

This is my first answer, but I have been reading this site for a while and think I know what I'm doing. At least it beats befunge and SQL...

Unfortunately, like other answers, this one does not work for 24547284284866560000000000 due to java'a built in restrictions on how large integers can get.

Saved 36 bytes thanks to @JackAmmo

public int p(int n){if(n<10)return n;int i=1,t=1,s=(int)Math.log10(n)+1,r[]=new int[s];for(;i<=s;){int a=(int)Math.pow(10,i);r[s-i++]=n%a/(a/10);}for(i=0;i<s-1;i++)t*=Math.pow(r[i],r[++i]);if(s%2==1)t*=r[s-1];return n==t?n:p(t);}

Ungolfed Explanation

public int powertrain(int input){
    //handles negative and 1-digit cases
    if(input<10)return input;
    //initialize output variable       
    int total=1;
    // get "length" of number. Shorter than getting length of string representation
    int size=(int)Math.log10(input)+1;
    //initialize array to store digits
    int[] array=new int[size];
    //Now, because Java doesn't have support
    // for the "**" operation, and the way of turning
    // an integer into a string takes too many bytes,
    // I decided just to put every digit into an array with
    // math and iterate from there
    for(int i=1;i<=size;){
        int place=(int)Math.pow(10,i);
        //crazy math. Saved 1 byte by incrementing i when accessed
        array[size-i++]=input%place/(place/10);
    }
    for(int i=0;i<size-1;i++)
        //This is where the train happens.
        //Saved 1 byte by incrementing while accessing 
        //again, instead of i+=2 and i+1
        total*=Math.pow(array[i],array[++i]);
    //Make sure last number isn't left out if size is odd
    if(size%2==1)
        total*=array[size-1];
    //if we end up with same number, stop.
    //otherwise, keep recurring
    return input==total?input:powertrain(total);
}

Blue

Posted 2016-03-08T07:23:23.937

Reputation: 1 986

In your first if...else if(n<10)return n;else{...} the else is unneccessary since logically everything in that else block would only run anyway when n<10 is false. Removing the else and the 2 matching braces will save you 6 bytes. There's a similar situation with your last if...else if(n==t)return n;else return p(t); remove the else and the space after it to save another 5 bytes. In fact you can shorten it even further if you use the triadic operator instead of the if...else like so return n==t?n:p(t); – Jack Ammo – 2016-03-13T00:27:28.183

you can save a few more bytes (17 i think) by declaring t,s,r, and the for loop's i together int t=i=1,s=(int)Math.log10(n)+1,r[]=new int[s];for(;i<=s;){...}for(i=0;...)... – Jack Ammo – 2016-03-13T00:46:24.950

@JackAmmo I wasn't aware variables could be declared like that, I'll have to try it. Thanks for your help! – Blue – 2016-03-13T00:59:36.867

yeah, you just have to be careful with the order of declaring them if you're using one to initialize another (like how r uses s to define it's length) – Jack Ammo – 2016-03-13T01:07:13.313

for arbitrary large numbers, you should look into java's BigInteger class http://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html

– Jack Ammo – 2016-03-13T02:05:28.453

@JackAmmo unfortunately, code golf – Blue – 2016-03-13T02:07:04.080

2

JavaScript (ES6) 71

A recursive function, stopping when a repetition is found. This could not work for longer loops (2 or more value repeating) but it seems this could not happen, at least in the limited range of javascript number precision (17 digits)

f=n=>[...n+'1'].map((c,i)=>i&1?r*=Math.pow(d,c):d=c,r=1)&&n-r?f(r):n

Test

f=n=>[...n+'1'].map((c,i)=>i&1?r*=Math.pow(d,c):d=c,r=1)&&n-r?f(r):n

function go()
{
  v=+I.value
  R.textContent=f(v)
}  

go()
<input id=I value="1234"><button onclick="go()">Go</button>
<span id=R></span>

edc65

Posted 2016-03-08T07:23:23.937

Reputation: 31 086

Nice of that +'1' to kill two birds with one stone! – Neil – 2016-03-11T22:38:58.387

I don't know whether you'd investigated it already but the best I could do with replace was 1 byte longer: f=n=>`${n}1`.replace(/../g,([x,y])=>r*=Math.pow(x,y),r=1)&&n-r?f(r):n – Neil – 2016-03-11T22:45:38.080

@Neil I tried hard too, but that template string is a new idea ... – edc65 – 2016-03-12T01:12:58.193

1

Haskell, 100 79 77 bytes

g x|x==h x=x|1<2=g$h x;h=i.map(read.(:[])).show;i[]=1;i[a]=a;i(a:b:c)=a^b*i c

Not golfed:

g x|x==h x=x|1<2=g$h x
h=i.map(read.(:[])).show
i[]=1
i[a]=a
i(a:b:c)=a^b*i c

This function splits the input into digits and does the trick via i.

EDIT: Thanks to nimi for some tips.

Renzeee

Posted 2016-03-08T07:23:23.937

Reputation: 599

A few tips: a) i(a:[])=a is i[a]=a, b) no need for max 1, because 0^0 = 1 in Haskell, c) replace (:[]) with pure, d) move the let within g into a separate function and replace the if ... then ... else with guards: h=i.map(read.pure).show ; g x|x==h x=x|1<2=h x – nimi – 2016-03-09T18:23:42.767

pure is not in Prelude, but the rest of the tips work, thanks. I was trying to do it with guards, but ended up using ; before the guard and that didn't work, but now I know how it should work. – Renzeee – 2016-03-11T08:49:05.810

pure is in the Prelude that comes with base-4.8.2.0. Don't know when it was introduced. You don't need the ( ) in i([a])=a. – nimi – 2016-03-11T17:02:58.680

1

MATL, 21 bytes

tt0>*:"V!UtQgv9L2#)^p

It may take a few seconds to produce the output.

EDIT (July 30, 2016): the linked code replaces 9L by 1L to adapt to recent changes in the language.

Try it online!

This uses the following two tricks to reduce byte count at the expense of code efficiency:

  • Iterate n times instead of waiting until a cycle is found. This is acceptable as per OP's comments.
  • For an odd number of digits a final 1 would have to be appended to complete the final power operation. Instead of that, the number of added 1 is the number of digits. This ensures an even number, so all power operations can be done (even if the last ones are unnecessary 1^1 operations).

Code:

t         % implicitly take input x. Duplicate
t0>*      % duplicate. Is it greater than 0? Multiply. This gives 0 if input is negative,
          % or leaves the input unchanged otherwise
:         % Generate array [1,2,...,x]
"         % for each (repeat x times)
  V       %   convert x to string
  !       %   transpose into column char array
  U       %   convert each char into number
  tQg     %   duplicate. Add 1 so that no entry is zero. Convert to logical: gives ones
  v       %   concatenate vertically
  9L2#)   %   separate odd-indexed and even-indexed entries
  ^       %   element-wise power
  p       %   product of all entries
          % implicitly end for each
          % implicitly display

Luis Mendo

Posted 2016-03-08T07:23:23.937

Reputation: 87 464

Uh... heh heh heh... when I said "loops of numbers", I meant numbers that went like this - a, b, a, b ad infinitum (more than one term). If one term is repeated, then you should output that number. Sorry if that wasn't really clear. – clismique – 2016-03-11T23:26:05.313

If one term is repeated, I'm outputting that number. I output the result after many iterations – Luis Mendo – 2016-03-12T14:04:10.093

Oh, I understand now... just asking, how many iterations would it be (approx.)? Because when I type in 2592 into the input, it doesn't seem to output anything for quite a while. – clismique – 2016-03-13T00:51:57.803

The number of iterations is the input number, so 2592 in that case. Yes, it takes a while – Luis Mendo – 2016-03-13T03:58:57.760

1

Mathematica, 77 bytes

Times@@(If[#2<1,1,#^#2]&)@@@Partition[IntegerDigits@#,2,2,1,1]&~FixedPoint~#&

Anonymous function. Not too complicated.

LegionMammal978

Posted 2016-03-08T07:23:23.937

Reputation: 15 731

Even so, can I still have an explanation? – clismique – 2016-03-14T09:05:00.973

1

Befunge 720 490 bytes

Couldn't resist to do one more after the Never tell me the odds thing. So, I've optimized the "ASCII-fier" of the previous one. In this case I saw no need to let the instruction pointer run over the digits to read them, so I haven't taken the effort to make them human readable. So it's more of a digitifier, now.

Again, if you guys want an explanation, let me know in the comments, I'll try to create some helpful descriptions. You can copy paste the code into the interpreter. I've found that the example 24547284284866560000000000 outputs 0, but that seems to be a problem with getting such a large value from a point on the grid, as you can clearly see the correct value being stored in the final steps.

v                                                    //top row is used for "variables"
>&:0`#v_.@                                           //initialize the counter                          
v     <                           g01_v#-p01:  <     //on our way back to the digitifier, check if we're done
>::>210p>55+%:10g0p-55+/:v            >10g.@         //digitifier, creates a series of ASCII characters at the top line, one for each digit in the source
        ^p01+1g01    _v#:<
v1$$                  <                              //forget some remainders of the digitifier, put 1 on the stack as a base of calculation
                      v p0-1g01-1g0-1g01*g0g01<      //taking powers of each pair of digit
>10g2-!#v_10g1-!#v_  1>                10g1-0g|
^                                  p01-2g01  *<
        >10g0g*  >                             ^     //extra multiplication with last digit if the number of digits was odd

This version also supports negative input. It's a great improvement on the previous version, if I say so myself. At least 1 bug was fixed and the size was reduced greatly.

rael_kid

Posted 2016-03-08T07:23:23.937

Reputation: 341

How many bytes more will it take for the thing to input negative numbers? – clismique – 2016-03-11T06:25:16.617

I'm not sure to be honest. I had some problems with negative numbers and writing them somewhere in the grid. I'll try it again. – rael_kid – 2016-03-11T08:07:42.830

I just found another bug, too. I did manage to add support for negative numbers. I'll post an update soon! It'll probably be the same amount of bytes, since I count the entire grid. – rael_kid – 2016-03-11T08:15:38.167

1

Mathematica, 74 bytes

0~f~0=f[]=1
f@n_=n
f[a_,b_,c___]:=f[c]a^b
#//.i_/;i>0:>f@@IntegerDigits@i&

Explanation

This solution uses a helper function f, which takes the digits of the number as arguments and applies one iteration of the power train operation. The last line is a pure function that is crafted to exploit the ReplaceRepeated function (or //. for short), which applies a rule to an expression (in this case the argument # of the pure function) until it doesn't change anymore. The rule i_/;i>0:>f@@IntegerDigits@i replaces anything non-negative with the function f applied to its decimal digits.

murphy

Posted 2016-03-08T07:23:23.937

Reputation: 635

Line 2 doesn't work (use :=) – CalculatorFeline – 2016-03-14T01:00:06.337

Explanation, please? – clismique – 2016-03-14T09:04:41.410

@CatsAreFluffy I don't see your problem with line 2. It works fine for me! – murphy – 2016-03-14T09:54:46.333

SetDelayed::write: Tag Times in n f[a_,b_,c___] is Protected. >>, Set::write: Tag Times in 1 f[n_] is Protected. >> The second error disappears when i use :=vs=. – CalculatorFeline – 2016-03-14T15:07:19.510

Sorry, can't reproduce that error. But your output indicates that the line-breaks are part of the problem. Please try the version with ;s instead of the line-breaks: 0~f~0=f[]=1;f@n_=n;f[a_,b_,c___]:=f[c]a^b;#//.i_/;i>0:>f@@IntegerDigits@i& – murphy – 2016-03-14T18:54:47.790

0

Python 3, 169 161 bytes

def f(s):
 o=[['1',s]['-'in s]]
 while s not in o:
  o+=[s];s+='1'*(len(s)%2==1);r=1;
  for i,j in zip(s[::2],s[1::2]):r*=int(i)**int(j);s=str(r);
 return o[-1]

Ungoldfed

def f(s):
 o=[['1',s]['-'in s]]
 while s not in o:
  o+=[s]
  s+='1'*(len(s)%2==1)
  r=1
  for i,j in zip(s[::2],s[1::2]):
   r*=int(i)**int(j)
  s=str(r)
 return o[-1]

Results

>>> [f(i) for i in ['135', '1234', '642', '2592', '-15']]
['5', '8', '2592', '2592', '-15']

Erwan

Posted 2016-03-08T07:23:23.937

Reputation: 691

@PeterTaylor Fixed! – Erwan – 2016-03-08T13:44:27.117

You can put multiple statements in one line if you seperate them with a ; This way you saves you the intendation whitespaces. Also you can put the body of the for loop on that same line. – Denker – 2016-03-10T09:17:31.220

Suggested golfing:def f(s,o=[['1',s]["-"in s]],n=int): while s not in o: o+=[s];s+=1*(len(s)%2<1);r=1 for i,j in zip(s[::2],s[1::2]):r*=n(i)**n(j) s=str(r) return o[-1] – CalculatorFeline – 2016-03-10T17:26:33.290

@CatsAreFluffy o=[['1',s]["-"in s]] in default argument don't work for me it raise a error s not defined – Erwan – 2016-03-11T06:58:31.680

Oops, move o to the next line. – CalculatorFeline – 2016-03-11T14:32:01.890

0

Oracle SQL 11.2, 456 bytes

WITH v(n,c,i,f,t)AS(SELECT:1+0,CEIL(LENGTH(:1)/2),1,'1',0 FROM DUAL UNION ALL SELECT DECODE(SIGN(c-i+1),-1,t,n),DECODE(SIGN(c-i+1),-1,CEIL(LENGTH(t)/2),c),DECODE(SIGN(c-i+1),-1,1,i+1),DECODE(SIGN(c-i+1),-1,'1',RTRIM(f||'*'||NVL(POWER(SUBSTR(n,i*2-1,1),SUBSTR(n,i*2,1)),SUBSTR(n,i*2-1,1)),'*')),DECODE(SIGN(c-i+1),-1,0,TO_NUMBER(column_value))FROM v,XMLTABLE(f)WHERE i<=c+2 AND:1>9)CYCLE n,c,i,f,t SET s TO 1 DEFAULT 0SELECT NVL(SUM(n),:1) FROM v WHERE s=1;

Un-golfed

WITH v(n,c,i,f,t) AS
(
  SELECT :1+0,CEIL(LENGTH(:1)/2),1,'1',0 FROM DUAL
  UNION ALL
  SELECT DECODE(SIGN(c-i+1),-1,t,n),
         DECODE(SIGN(c-i+1),-1,CEIL(LENGTH(t)/2),c),
         DECODE(SIGN(c-i+1),-1,1,i+1),
         DECODE(SIGN(c-i+1),-1,'1',RTRIM(f||'*'||NVL(POWER(SUBSTR(n,i*2-1,1),SUBSTR(n,i*2,1)),SUBSTR(n,i*2-1,1)),'*')),
         DECODE(SIGN(c-i+1),-1,0,TO_NUMBER(column_value))
  FROM v,XMLTABLE(f) WHERE i<=c+2 AND :1>9 
)  
CYCLE n,c,i,f,t SET s TO 1 DEFAULT 0
SELECT NVL(SUM(n),:1) FROM v WHERE s=1;

v is a recursive view, parameters are

n : number to split in 2 digits parts

c : number of 2 digits parts

i : current 2 digits part to compute

f : string concatenating the powers with * as separator

t : evaluation of f

The DECODEs switch to the next number to split and compute when all the parts of the current number are done.

XMLTABLE(f) takes an expression an evaluates it, putting the result in the pseudo column "column_value". It's the golfed version of http://tkyte.blogspot.fr/2010/04/evaluating-expression-like-calculator.html

CYCLE is the oracle build in cycle detection and is used as the exit condition.

Since the result for :1<10 is :1 and v returns no row for those cases, SUM forces a row with NULL as the value. NVL returns :1 as the result if the row is null.

Jeto

Posted 2016-03-08T07:23:23.937

Reputation: 1 601

Where's the explanation? – clismique – 2016-03-11T23:21:24.717