42
\$\begingroup\$

Background:

Standard operation math like basic addition and multiplication in the real world work like these:

12 + 123 = 135

and

12 * 123 = 1476

That's not interesting and boring! Many schools are already interpreting this as practice, practice, practice of formal algorithms. That implies a pretty rigid and boring mathematical diet and is not what is intended in this challenge. Get ready to play some fun on our beloved site.

Consider the process of adding two positive integer numbers, then adding again all the digits of its result. Repeating with the addition until only a single digit is obtained. For example:

  1. The result of 12 + 123 is 135.
  2. Adding all the digits of 135 we obtain 1 + 3 + 5 = 9.

The number of steps required to obtain a single digit value 9 in this repeated addition is 2.

As with the previous process of the addition, the multiplication of two positive integer numbers follows the same process. Multiply all the digits of its result and then repeating this process until only a single digit remains. Take the above example:

  1. The result of 12 * 123 is 1476.
  2. Multiply all the digits of 1476 we obtain 1 * 4 * 7 * 6 = 168.
  3. Multiply again all the digits of 168 we obtain 1 * 6 * 8 = 48.
  4. Multiply again all the digits of 48 we obtain 4 * 8 = 32.
  5. Multiply once again all the digits of 32 we obtain 3 * 2 = 6.

The number of steps required to obtain a single digit value 6 this repeated multiplication is 5.

For this challenge's sake and avoiding any misuse of math notations, I introduce these two dummy notations: (+) and (*), but you may use any notation you like, which work like the followings:

  1. The operation of repeated addition process to obtain a single value is 12 (+) 123 = 9.
  2. The operation of repeated multiplication process to obtain a single value is 12 (*) 123 = 6.

Challenge:

The challenge is to write either a program or a function which can perform both of operations as explained in the background section: (+) and (*).

Input:

The inputs of the program or the function are two positive integers and one operation either (+) and (*). The format of the input is an arbitrary choice of the programmer. You may format the input, for example, a (+) b or F(a, (+), b) or any format you wish.

Output:

The output of the program or the function must contain the result of operation and the number of steps required with freestyle format as you wish.

Test Cases (ignore the input and output format):

    81 (+) 31       -->   (4 ; 2)
    351 (+) 14568   -->   (6 ; 3)
    21 (*) 111      -->   (8 ; 3)
    136 (*) 2356    -->   (0 ; 2)

General rules:

  • This is , so the shortest answer in bytes wins the challenge.
    Don't let esolangs discourage you from posting an answer with regular languages. Enjoy this challenge by providing an answer as short as possible with your programming language. If you post a clever answer and a clear explanation, your answer will be appreciated (hence the upvotes) regardless of the programming language you use.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/ method with the proper parameters, full programs, etc. The choice is yours.
  • If possible, your program can properly handle large numbers. If not, that will just be fine.

Let the game begin!!

\$\endgroup\$
8
  • 1
    \$\begingroup\$ The repeated addition part (digital root) is essentially a duplicate of codegolf.stackexchange.com/q/1128/194 \$\endgroup\$ Commented Aug 24, 2016 at 9:49
  • 4
    \$\begingroup\$ Great first question! And I recognize the general rules format and sentences from my own Questions. ;) \$\endgroup\$ Commented Aug 24, 2016 at 11:10
  • 4
    \$\begingroup\$ @KevinCruijssen Yup. that's right. Since it has no copyright so I duplicate it without your permission. Hehehe :D \$\endgroup\$ Commented Aug 24, 2016 at 11:11
  • 1
    \$\begingroup\$ Related: Manhattan and Fuzzy-Logic. \$\endgroup\$
    – Adám
    Commented Aug 24, 2016 at 13:26
  • 4
    \$\begingroup\$ @Anastasiya-Romanova秀 "no copyright"? In XXI century? Nope; everything here is CC-BY-SA 3.0. Permission is granted when the content is submitted. Check the site footer. \$\endgroup\$ Commented Aug 24, 2016 at 14:42

26 Answers 26

12
\$\begingroup\$

Dyalog APL, 33 32 30 29 bytes

This extends APL to include the prefix notation +/A n₁ n₂ and ×/A n₁ n₂. (In fact, you can use any operation to the left of the /A.) Returns a list of {result, repetition count}.

A←{(⊃,≢)⍺⍺{∪⍵,⍨⍺⍺⍎¨⍕⊃⍵}⍣≡⍺⍺⍵}

A←{ define a higher-order function in terms of left-hand function ⍺⍺, and right-hand argument

(⊃,≢) the first element of, followed by the count of

⍺⍺{ the supplied function (+/ for sum or ×/ for product) fed to the higher-order function

the unique elements of

⍵,⍨ the argument appended to

⍺⍺ the fed function applied to

⍎¨ the evaluation of each character of

the character representation of

⊃⍵ the first element of the argument

}⍣≡ applied repeatedly until the result is identical to the argument, beginning with

⍺⍺⍵ the originally fed function (+/ or ×/) applied to the original argument

} [end of higher-order function definition]

TryAPL online! ( has been emulated with e for security reasons.)

Thanks to @ngn for saving a byte.


0 bytes (in jest)

Dyalog APL actually already has full support for Anastasiyan math; instead of (+) and (×), it uses +{n←0⋄n,⍺⍺{n+←1⋄⍺⍺/⍎¨⍕⍵}⍣=⍵⍺⍺⍨⍺} and ×{n←0⋄n,⍺⍺{n+←1⋄⍺⍺/⍎¨⍕⍵}⍣=⍵⍺⍺⍨⍺}.

Try 81 +{(⊃,≢)⍺⍺{∪⍵,⍨⍺⍺e¨⍕⊃⍵}⍣≡⍺⍺/⍺⍵} 31 and 21 ×{n←0⋄n,⍺⍺{n+←1⋄⍺⍺/e¨⍕⍵}⍣=⍵⍺⍺⍨⍺} 111.

\$\endgroup\$
8
  • \$\begingroup\$ Thanks for the answer, (+1). Can it handle large number inputs? \$\endgroup\$ Commented Aug 24, 2016 at 10:04
  • 1
    \$\begingroup\$ If you set ⎕FR←1287 (i.e. use IEEE 754-2008 128-bit decimal Floating-point Representation) and ⎕PP←34 (i.e. use 34 characters' Print Precision), you can use integers below 10³⁴. \$\endgroup\$
    – Adám
    Commented Aug 24, 2016 at 10:13
  • 3
    \$\begingroup\$ @KevinCruijssen The OP allows any input notation. So, if a language happened to support default-notation Anastasiyan math out-of-the box, the multi-char glyph (+) would be the Anastasiyan +. Dyalog APL does support Anastasiyan math, but it uses a different multi-char glyph, just as * means power and you need × for multiplication, while / means replication and you need ÷ for division. \$\endgroup\$
    – Adám
    Commented Aug 24, 2016 at 14:21
  • 1
    \$\begingroup\$ @Adám Ah ok, that makes sense. It's kinda bending OP's rules, but not breaking them. It's still pretty odd that instead of (+) you have +{n←0⋄n,⍺⍺{n+←1⋄⍺⍺/⍎¨⍕⍵}⍣=⍵⍺⍺⍨⍺} as input, but since OP indeed stated any input format will do, you can use the function as parameter. Hmm, I wonder if this is also possible in other programming languages which support functions as input. \$\endgroup\$ Commented Aug 24, 2016 at 14:26
  • 1
    \$\begingroup\$ @Acccumulation Well, sure, if you make a golfing language for the task. However, here we are just dealing with a task description which is permissive. Btw, APL isn't a golfing language. \$\endgroup\$
    – Adám
    Commented Apr 16, 2018 at 16:29
10
\$\begingroup\$

Haskell, 108 bytes

f=map(read.pure).show
g h=(\x->(h.f$last x,length x+1)).takeWhile(>10).iterate(h.f)
(a#b)o=g(foldr1 o)$o a b

Defines the function # which first takes a and b and then the operator o. Fun fact: this works with any operator (actually, any function) you want!

\$\endgroup\$
2
  • \$\begingroup\$ Thanks for the answer, (+1). Can it handle large number inputs? \$\endgroup\$ Commented Aug 24, 2016 at 10:04
  • 5
    \$\begingroup\$ @Anastasiya-Romanova秀 Yes, it can handle numbers as big as your RAM since Haskell's Integer type is unbounded. \$\endgroup\$
    – ThreeFx
    Commented Aug 24, 2016 at 10:28
8
\$\begingroup\$

Pyke, 16 bytes

RE`DltImbRoKr)oh

Try it here!

RE               - evaluate the input as Pyke code
                 -  (`B` is product and `s` is sum, the second line is a tuple)
  `              - i = str(^)
    ltI      )   - if len(i) != 1:
       mb        -   map(i, int)
         R       -   get the `B` or `s` from input
          oK     -   o++
            r    -   goto_start()
              oh - o++ + 1

Takes multiply as B and add as s. The two numerical inputs are separated by commas.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Nice! Can we get an explanation? \$\endgroup\$
    – Emigna
    Commented Aug 24, 2016 at 9:57
  • \$\begingroup\$ Thanks for the answer, (+1). Can it handle large number inputs? \$\endgroup\$ Commented Aug 24, 2016 at 10:03
  • \$\begingroup\$ @Anastasiya-Romanova秀 it should be able to handle arbitrary numbers \$\endgroup\$
    – Blue
    Commented Aug 24, 2016 at 10:06
  • \$\begingroup\$ I cannot test your code because the web is blocked since it's in violation of my parents' internet usage policy. T_T \$\endgroup\$ Commented Aug 24, 2016 at 10:10
  • \$\begingroup\$ Something like this: Web Page Blocked! You have tried to access a web page which is in violation of your internet usage policy. URL: pyke.catbus.co.uk/?code=RE%60DltImbRoKr%29oh&input=B%0A21%2C+111&warnings=0 Category: Unrated \$\endgroup\$ Commented Aug 24, 2016 at 10:13
8
\$\begingroup\$

JavaScript (ES6), 59

Recursive function, the input format is tailored to simplify the recursive call:

  • operator : '+' or '*'
  • operands : array of two values
f=(o,v,s=1,t=eval(v.join(o)))=>t>9?f(o,[...t+''],s+1):[t,s]

Test

f=(o,v,s=1,t=eval(v.join(o)))=>t>9?f(o,[...t+''],s+1):[t,s]

;[
  [81,'+',31,     /* -> */ 4, 2]
, [351,'+',14568, /* -> */ 6, 3]
, [21,'*',111,    /* -> */ 8, 3]
, [136,'*',2356,  /* -> */ 0, 2]
].forEach(t=>{
  var [a,o,b,k1,k2] = t,
      [r,s]=f(o,[a,b]);
  console.log(k1==r && k2==s ? 'OK':'KO',a,o,b,'->',r,s)
})  
  

\$\endgroup\$
2
  • \$\begingroup\$ Thanks for the answer, (+1). Can it handle large number inputs? \$\endgroup\$ Commented Aug 24, 2016 at 10:45
  • 1
    \$\begingroup\$ @Anastasiya-Romanova秀 up to the limit of javascript numeric format, 53 bits of precision (17 decimal digits) \$\endgroup\$
    – edc65
    Commented Aug 24, 2016 at 10:58
8
\$\begingroup\$

Python 2, 60 bytes

f=lambda s,c=0:s[1:]and f(min(s).join(`eval(s)`),c+1)or(s,c)

Input is a string like 81+31, output is a tuple of a singleton string and a counter (e.g., ('4', 2).

Test it on Ideone.

\$\endgroup\$
3
  • \$\begingroup\$ If taking input as an array of strings and a single string is allowed, e.g., f(['81', '31'],'+'), a further byte can be saved, but that feels like stretching the rules a bit too far... \$\endgroup\$
    – Dennis
    Commented Aug 25, 2016 at 1:54
  • \$\begingroup\$ "The format of the input is an arbitrary choice of the programmer" \$\endgroup\$ Commented Aug 25, 2016 at 11:48
  • \$\begingroup\$ ...in which case I'd even go as far and consider passing operator.add or operator.mul respectively ;) \$\endgroup\$ Commented Aug 25, 2016 at 11:58
7
\$\begingroup\$

Pyth, 16

eJ.uvjhQ`N.vQ)lJ

Takes input like "+ 123 12" for addition, and "* 123 12" for multiplication. Outputs like result<linefeed>steps.

Try it here, or run a Test Suite, but note that this relies on eval, so only the addition variant will work in the online interpreter. Multiplication works correctly with the offline interpreter.

This uses the cumulative reduction function to create a list of intermediate results, so for "+ 351 14568" we get [14919, 24, 6]. This works because single digit numbers are a fixed point of the Anastasiya addition and multiplication. Then we just get the last element of the array as well as the length of the array.

This will work for arbitrarily large numbers, at least until you run out of memory.

\$\endgroup\$
7
\$\begingroup\$

Jelly, 11 10 bytes

Dj⁹VµÐĿḊĖṪ

Input is a pair of numbers and either + or ×.

Try it online! or verify all test cases.

How it works

Dj⁹VµÐĿḊĖṪ  Main link. Left argument: [x, y] (integers). Right argument: + or ×

    µÐĿ     Repeatedly execute the chain to the left, initially with argument
            [x, y], then with the previous return value. Stop when the results are
            no longer unique, and return the array of all intermediate results.
D           Decimal; convert the integers [x, y] or the return value z to base 10.
 j⁹         Join, separating by the link's right argument, i.e., '+' or '×'.
   V        Evaluate the result. This casts the previous return value to string,
            so, e.g., [8, 1, '+', 3, 1] becomes "81+31" before evaluation.
       Ḋ    Dequeue; discard the first intermediate result, i.e., [x, y].
        Ė   Enumerate; prefix each integer in the array with its 1-based index.
         Ṫ  Tail; extract the last index-value pair.
\$\endgroup\$
7
\$\begingroup\$

ARM Machine Code, 48 bytes

Hex dump:

b570 2a00 bf0c 1840 4348 2101 230a e00c 3101 0015 fbb0 f6f3 fb06 0413 2a00 bf0c 192d 4365 0030 d1f5 0028 280a d2f0 bd70

This function doesn't depend any system calls or library functions. This is Thumb-2 code, which is a variable-length instruction encoding (2 or 4 bytes) for 32-bit ARM. Thus, the maximum value it can process is 2^32-1. 2 bytes could be dropped if it didn't conform to the AAPCS (46 bytes), since we wouldn't have to stack registers at the beginning.

Ungolfed assembly (GNU syntax):

.syntax unified
.text
.global anastasiya
.thumb_func
anastasiya:
    @Input:
    @r0 - First number
    @r1 - Second number
    @r2 - 0 for add, 1 for multiply
    @Output:
    @r0 - Resultant value
    @r1 - Number of steps
    push {r4,r5,r6,lr}
    cmp r2,#0
    ite eq @if r2==0
    addeq r0,r0,r1 @r0+=r1
    mulne r0,r0,r1 @else r0*=r1
    movs r1,#1 @r1 is the number of steps
    movs r3,#10
    b endloop
    loop:
        adds r1,r1,#1 @Increment number of steps
        movs r5,r2 @r5=1 if multiply, 0 if add
        parseDigits:
            udiv r6,r0,r3 @r6=r0/r3
            mls r4,r6,r3,r0 @r4=r0 - r6*r3
            @Last two operations were r4=r0%r3 (r3==10)
            cmp r2,#0
            ite eq @if r2==0
            addeq r5,r5,r4 @r5+=r4
            mulne r5,r5,r4 @else r5*=r4
            movs r0,r6 @r0=r6 (Set r0 to r0/10)
            bne parseDigits @while (r0!=0)
        @Now our new total is in r5
        movs r0,r5 @Put it in r0
    endloop:
        cmp r0,#10
        bhs loop @while (r0 >=10)
    pop {r4,r5,r6,pc} @Return

Testing script in C:

#include <stdio.h>
unsigned long long anastasiya(unsigned,unsigned,unsigned);

int main(void) {
    unsigned x,y,op;
    printf("Enter first operand, second operand, and 0 for addition or 1 for multiplication.\n");
    scanf("%u%u%u",&x,&y,&op);
    unsigned long long res = anastasiya(x,y,op);
    printf("Result = %u, steps = %u\n",(unsigned)res ,(unsigned)(res >> 32));
}
\$\endgroup\$
7
\$\begingroup\$

R, 175 167 164 140 134 127 126 119 bytes

function(G,S,D){i=1;O=switch(S,"+"=sum,prod);x=O(G,D);while(x>9){i=i+1;x=O(strtoi(strsplit(paste(x),"")[[1]]))};c(x,i)}

Ungolfed :

f=function(G,S,D) #The function takes : the left operand, the operation symbol (between quote marks)
                  #and then the right operand
i=1               #That's the counter

O=switch(S,"+"=sum,prod)     #`O` takes the value `sum` if `S` matches `+`, `prod` 
                             #(which is the next agument) if not. 
                                                        
x=O(G,D)                     #Does the first operation

while(nchar(x)>1)                 #While the number of character of the result 
                                  #of the operation is not of length 1, i.e., an integer :

    i=i+1                                    #Increase the counter
    x=O(strtoi(strsplit(paste(x),"")[[1]]))  #Apply the operation `O` to the first operation and 
                                             #the eventual subsequent ones

c(x,i)                                 #Outputs the result and the counter

ifelse is back ! Yeah !
Nop

Usage :

Special addition
> f(31,"+",81)
[1] 4 2

Special multiplication
> f(136,"*",2356)
[1] 0 2

Thanks a lot to @plannapus for golfing out 24 bytes !
-7 bytes thanks to a good idea from @Vlo !

\$\endgroup\$
11
  • \$\begingroup\$ Yes, please do add explanations since I love R! This is my second language after VBA. (+1) \$\endgroup\$ Commented Aug 24, 2016 at 10:21
  • 1
    \$\begingroup\$ @Anastasiya-Romanova 秀 : Done ! \$\endgroup\$
    – Rudier
    Commented Aug 24, 2016 at 12:31
  • \$\begingroup\$ @plannapus : Really nice ! Thanks a lot ! \$\endgroup\$
    – Rudier
    Commented Aug 24, 2016 at 14:29
  • 1
    \$\begingroup\$ @Frédéric nice use of strtoi! 4 more bytes are you have me beaten. \$\endgroup\$
    – plannapus
    Commented Aug 26, 2016 at 9:01
  • 1
    \$\begingroup\$ Looks like you can further golf off a byte by including the definition of O within the assignment of x in the first operation: x=(O=switch(S,sum,`*`))(G,D);. \$\endgroup\$
    – rturnbull
    Commented Sep 14, 2016 at 23:24
6
\$\begingroup\$

05AB1E, 20 15 bytes

[¼¹iOëP}Dg#S]¾‚

Explanation

[       Dg# ]    # loop until number is single digit
 ¼               # increase counter
  ¹iO            # if operation is addition, sum list
     ëP}         # else take product of list
           S     # split into a list of digits
             ¾‚  # pair final number with counter and output

Operator is 1 for addition, 0 for multiplication.

Try it online

\$\endgroup\$
3
  • \$\begingroup\$ Thanks for the answer, (+1). Can it handle large number inputs? \$\endgroup\$ Commented Aug 24, 2016 at 10:03
  • \$\begingroup\$ @Anastasiya-Romanova秀 I don't see a reason why not. Do you have an example? \$\endgroup\$
    – Emigna
    Commented Aug 24, 2016 at 10:04
  • \$\begingroup\$ Your program's been tested for that kind of inputs, so it perfects :) \$\endgroup\$ Commented Aug 24, 2016 at 10:07
4
\$\begingroup\$

Jelly, 17 bytes

+×⁵?µDSP⁵?$ÐĿµL;Ṫ

Try it online!

Given arguments like x y 1, this computes the Anastasiya sum x (+) y.

Given arguments like x y 0, this computes the Anastasiya product x (*) y.

Output is given as [number of steps, result].

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the answer, but your program output doesn't contain the number of steps required part? Am I missing something here? \$\endgroup\$ Commented Aug 24, 2016 at 10:57
4
\$\begingroup\$

R, 130 124 chars

A somewhat different approach from @Frédéric's:

f=function(a,f,b){b=c(a,b);n=1;while((m<-nchar(d<-switch(f,'(+)'=sum,prod)(b)))>1){b=d%%10^(1:m)%/%10^(1:m-1);n=n+1};c(d,n)}

Indented, with newlines:

f=function(a,f,b){
    b=c(a,b) # Take both numbers
    n=1 #Counter
    while((m<-nchar(d<-switch(f,'(+)'=sum,prod)(b)))>1){
#My own special digit splitter! (d is the result and m is the nb of char of d)
        b=d%%10^(1:m)%/%10^(1:m-1)
        n=n+1
    }
    c(d,n) #Print results
    }

Line 4 probably needs more explanations:

switch(f,'(+)'=sum,prod) #pick which operator to use
switch(f,'(+)'=sum,prod)(b) # apply it to b
d<-switch(f,'(+)'=sum,prod)(b) #Saves the result in d
nchar(d<-switch(f,'(+)'=sum,prod)(b))#Measures the number of character of d
m<-nchar(d<-switch(f,'(+)'=sum,prod)(b)) #Saves it in m
(m<-nchar(d<-switch(f,'(+)'=sum,prod)(b)))>1 #Checks if it is more than 1

Test cases:

> f(12,"(+)",123)
[1] 9 2
> f(12,"(*)",123)
[1] 6 5
> f(351,"(+)",14568)
[1] 6 3
\$\endgroup\$
7
  • \$\begingroup\$ Quite unfortunate you came late with this answer, but you have my upvote. Thanks for creating this in R. \$\endgroup\$ Commented Aug 24, 2016 at 15:46
  • \$\begingroup\$ Why unfortunate? \$\endgroup\$
    – plannapus
    Commented Aug 25, 2016 at 6:28
  • \$\begingroup\$ Because if you had come first, then you'd have got more upvotes \$\endgroup\$ Commented Aug 25, 2016 at 7:54
  • \$\begingroup\$ @Anastasiya-Romanova秀 Fair enough :) \$\endgroup\$
    – plannapus
    Commented Aug 25, 2016 at 8:14
  • \$\begingroup\$ Bonus points for having f be both the function name and one of its arguments :) \$\endgroup\$
    – JDL
    Commented Aug 26, 2016 at 15:16
4
\$\begingroup\$

Octave, 85 bytes MATLAB, 123, 114, 105, 94 bytes

Decided to translate this to Octace, to take advantage of the direct indexing, and incrementing capabilitites. Takes the input on the form: f(a,operator), where a = [number1, number2], and operator==1 gives the product, and operator==2 gives the sum.

function[x,i]=f(a,o)
g={@prod,@sum}{o};x=g(a);i=1;while(x=g(num2str(x)-48))>9;i++;end

Explanations:

g={@prod,@sum}{o} : Chooses the appropriate function, product or sum and assigns it to g

x=g(a) takes the sum or product of the inputs

i=1; ... i++ : Incrementer to count the number of steps

while(x=g(num2str(x)-48))>9;
          num2str(x)-48)     % turns a number 123 into an array [1 2 3].
        g(num2str(x)-48))    % Takes the sum or product of the array
      x=g(num2str(x)-48))    % Assign that value to the variable x
      x=g(num2str(x)-48))>9  % Checks if x > 9, continue looping if yes

Removed two newlines, a space, and placed both input numbers in a vector instead of separate arguments. This saved 9 bytes, thanks to pajonk! Removed k=@(x)... to save another 11 bytes thanks to beaker =) Finally, translated the whole thing to Octave to save another 9 bytes...

\$\endgroup\$
0
4
\$\begingroup\$

Java, 164 159 146 bytes

int[]p(int t,int m,String[]d){int r=m;for(String i:d){int x=Integer.decode(i);r=m<1?r+x:r*x;}return r>9?p(++t,m,(r+"").split("")):new int[]{r,t};}

First argument is just the counter, always 0

Second argument is method, 0 for ADD and 1 for MULTIPLY.

Third argument is an array of Strings, which contains the values to add/multiply.

Ungolfed

public static int[] p(int t, int m, String[] d) {
    int r = m;
    for (String i : d) {
        int x = Integer.decode(i);
        r = m < 1 ? r + x : r * x;
    }
    return (r + "").length() > 1 ? p(++t, m, (r + "").split("")) : new int[]{r, t};
}

thanks to @Kevin Cruijssen for cutting a few bytes.

thanks to @milk for shaving 5 bytes.

Test Program

public static final int ADD = 0;
public static final int MULTIPLY = 1;

public static void main(String[] args) {
    System.out.println(Arrays.toString(p(0, ADD, new String[]{"12", "123"}))); //9
    System.out.println(Arrays.toString(p(0, MULTIPLY, new String[]{"12", "123"}))); //6
}

public static int[] p(int t, int m, String[] d) {
    int r = m;
    for (String i : d) {
        int x = Integer.decode(i);
        r = m < 1 ? r + x : r * x;
    }
    return (r + "").length() > 1 ? p(++t, m, (r + "").split("")) : new int[]{r, t};
}
\$\endgroup\$
8
  • \$\begingroup\$ Nice, shorter than my Java answer. However, you're also supposed to print the steps as well as the answer which is currently missing from your answer.. \$\endgroup\$ Commented Aug 24, 2016 at 12:11
  • \$\begingroup\$ @KevinCruijssen Ahh. That's boring.. I'll try fix that now. \$\endgroup\$
    – Shaun Wild
    Commented Aug 24, 2016 at 12:14
  • \$\begingroup\$ Btw, you can golf your current answer a bit. m==0 can be m<1, and Integer.parseInt can be Integer.decode. \$\endgroup\$ Commented Aug 24, 2016 at 12:14
  • \$\begingroup\$ I don't use Java much, but do you need that j var at the end? Inlining (r+"") twice looks like it would shave a few bytes. \$\endgroup\$
    – milk
    Commented Aug 25, 2016 at 1:59
  • 1
    \$\begingroup\$ Can we not change my posts in future? If you want to suggest an edit do so in the comments. \$\endgroup\$
    – Shaun Wild
    Commented Sep 2, 2016 at 8:28
3
\$\begingroup\$

Python, 160 146 129 bytes

def r(s):
 n=str(eval(s));c=0
 while n[1:]:exec("n=str(reduce(lambda a,b:a%sb,map(int,list(n))))"%"*+"["+"in s]);c+=1
 return n,c

Will post an explanation soon.

Input is in the form 12+12 or 5*35 (with normal + and * signs), and assumes that those are the only two operators.

It can handle number inputs as large as your computer's memory allows.

I'm almost certainly confident that this can be further.

EDIT: 16 31 bytes saved thanks to @Copper.

\$\endgroup\$
9
  • \$\begingroup\$ Thanks for the answer, (+1). Can it handle large number inputs? \$\endgroup\$ Commented Aug 24, 2016 at 10:47
  • \$\begingroup\$ @Anastasiya-Romanova秀 Uhmmm... I'm fairly sure they can. Can you give me examples of large inputs? I'll try and calculate from those. \$\endgroup\$
    – clismique
    Commented Aug 24, 2016 at 10:50
  • \$\begingroup\$ Maybe: 3218753647208435810122106*29349566754? \$\endgroup\$ Commented Aug 24, 2016 at 10:54
  • 1
    \$\begingroup\$ @Anastasiya-Romanova秀 Yeah, it worked in ~0.5 seconds, didn't properly time it. \$\endgroup\$
    – clismique
    Commented Aug 24, 2016 at 11:01
  • \$\begingroup\$ You can change "+" if "+" in s else "*" to "*+"["+"in s], and then instead of assigning it to t, just add it inline in the exec call. \$\endgroup\$
    – Copper
    Commented Aug 24, 2016 at 11:14
3
\$\begingroup\$

R, 110 bytes

Using @plannapus' splitter.

function(A,F,B){r=Reduce;x=r(F,A,B);y=1;while(x>9){m=nchar(x);x=r(F,x%%10^(1:m)%/%10^(1:m-1));y=y+1};cat(x,y)}

f=function(A,F,B){
  r=Reduce                                  # Shortcut for Reduce
  x=r(F,A,B)                                # A operator B
  y=1                                       # Initiate counter
  while(x>9)                                # If number of digits > 2, or number > 9
  {m=nchar(x)                               # Count number of digits
    x=r(F,x%%10^(1:m)%/%10^(1:m-1))         # @plannapus's splitter, then feed into the A operator B operator C, etc while condition true
    y=y+1}                                  # Increment counter
  cat(x,y)}                                 # Print

Output

> f(136,"*",2356)
0 2
> f(31,"+",81)
4 2
> f(2,"+",3)
5 1
> (function(A,F,B){r=Reduce;x=r(F,A,B);y=1;while(x>9){m=nchar(x);x=r(F,x%%10^(1:m)%/%10^(1:m-1));y=y+1};cat(x,y)})(21,"*",111)
8 3

edit: I can't count.

\$\endgroup\$
1
  • \$\begingroup\$ R is fantastic because allowing us to shorten its function, something that's valuable in golfing. (+1) \$\endgroup\$ Commented Aug 26, 2016 at 20:40
3
\$\begingroup\$

Clojure 126 bytes

(defn f [o a b] (loop [n (o a b) c 1] (if (< n 10) [n c] (recur (reduce #(o %1 %2) (map #(- (int %) 48) (str n))) (inc c)))))

Function is called like so:

(f + 81 31)

Here is the code ungolfed:

(defn f [o a b]
  (loop [n (o a b) c 1]
    (if (< n 10)
      [n c]
      (recur (reduce #(o %1 %2)
                     (map #(- (int %) 48) (str n)))
             (inc c)))))

(def test-cases [[+ 81 31]
                 [+ 351 14568]
                 [* 21 111]
                 [* 136 2356]])

(map #(apply f %) test-cases)
;;=> ([4 2] [6 3] [8 3] [0 2])

Bear in mind that Clojure is still new to me, so this is likely not the best solution. The challenge was fun all the same. Additionally, the code ran with very large numbers without any difficulty.

\$\endgroup\$
1
  • \$\begingroup\$ This is very late, but you can reduces most of the spaces in there. \$\endgroup\$
    – clismique
    Commented Dec 25, 2016 at 3:26
2
\$\begingroup\$

Perl 6 53 bytes

{$/=(&^b($^a,$^c),{[[&b]] .comb}...10>*);$/[*-1],+$/}

Since ( 12, &[+], 123 ) is acceptable for the input, I can get it down to 53 bytes.
( &[+] is short for &infix:<+> which is a "reverence" to the numeric infix addition operator )

If the second argument had to be a string (+) it would be 87 bytes

{my&b=::("&infix:<$^b.substr(1,1)>");$/=(b($^a,$^c),{[[&b]] .comb}...10>*);$/[*-1],+$/}

Explanation:

# bare block lambda with 3 parameters declared using placeholder syntax
{
  # store list into 「$/」
  # ( used 「$/」 so that I don't have to declare a variable )
  $/ = (

    # declare second placeholder parameter, and call it
    &^b(
      # with the first and third placeholder parameters
      $^a, $^c
    ),

    # bare block lambda with implicit parameter 「$_」
    {
      # list reduce using the second parameter from outer block
      [[&b]]

      # a list of the digits of 「$_」 (implicit method call)
      .comb
    }

    # keep doing that until
    ...

    # it produces something smaller than 10
    # ( Whatever lambda )
    10 > *
  );

  # returns

  # final result ( last value from list )
  $/[ * - 1 ],
  # and count of values in list
  +$/
}

Test:

#! /usr/bin/env perl6
use v6.c;
use Test;

my &anastasiya-math = {$/=(&^b($^a,$^c),{[[&b]] .comb}...10>*);$/[*-1],+$/}

my @test = (
  (  81, &[+], 31    ) => (4, 2),
  ( 351, &[+], 14568 ) => (6, 3),
  (  21, &[*], 111   ) => (8, 3),
  ( 136, &[*], 2356  ) => (0, 2),
);

plan +@test;

for @test -> $_ ( :key(@input), :value(@expected) ) {
  cmp-ok anastasiya-math(|@input), &[»==«], @expected;
}

Normal Usage:

# override built-in Bag operator 「(+)」 in current lexical scope
my &infix:<(+)> = &anastasiya-math.assuming: *, &[+], *;

# add a new operator
my &infix:<(*)> = &anastasiya-math.assuming: *, &[*], *;

say 12 (+) 123; # (9 2)
say 12 (*) 123; # (6 5)
\$\endgroup\$
2
\$\begingroup\$

Python 2, 107 97 bytes

g=lambda x,o,i=1:x<10and[x,i]or g(eval(o.join(`x`)),o,i+1)
lambda a,o,b:g(eval('%s'*3%(a,o,b)),o)

An anonymous function that takes input via argument of a first operand a, an operator o ('+' or '*') and a second operand b, and returns a list of the form [result, steps].

How it works

The anonymous function creates a string by concatenating the operands with the operator between them, and then evaluates it; this is the first step described in the question. Then, this value and the operator are passed to the recursive function g. Here, a counter i, which is incremented for every recursive call, is used. If the input is less than 10, a single digit must have been reached, so this and i are returned. If not, the input is converted to a string and each character in this string is joined with the operator, giving the desired calculation, which is then evaluated and passed to the function recursively.

Try it on Ideone

\$\endgroup\$
1
  • \$\begingroup\$ (+1) while waiting the explanation :) \$\endgroup\$ Commented Aug 25, 2016 at 1:25
2
\$\begingroup\$

Groovy, 102 bytes

def p,e,r;p={t,m,d->e=d*.toInteger();r=m<1?e.sum():e.inject{a,b->a*b};r>9?p(++t,m,""+r as List):[r,t]}

Degolfed

def p,e,r
p = { t, m, d ->
    e = d*.toInteger()
    r = (
            m<1
                ? e.sum()
                : e.inject { a, b -> a * b }
        )
    r > 9
        ? p(++t, m, "" + r as List)
        : [r,t]
}

Explanation

Based on @Sean Bean 's excellent solution for Java.

  • p: The closure (function, lambda, whatever) that implements the solution
  • t: The current call depth (number of iterations), p should always be invoked with t=1
  • m: The operation to perform, 0 for "add", 1 for "multiply"
  • d: The list of operands, each operand is a String object
  • e: The elements of d, each converted to an Integer
  • r: The sum or product of e, depending on the operation m
  • result statement, starting with r > 9:
    • If multi-digit (r > 9), reinvoke, incrementing depth t and converting r to a list of digit strings (and return result).
    • If single-digit, return r and t as a list.

Test Program

final ADD = 0
final MULTIPLY = 1
println p(1, ADD, ["12", "123"]) //9, 2
println p(1, MULTIPLY, ["12", "123"]) //6, 5
println p(1, ADD, ["2", "3"]) //5, 1

Results

[9, 2]
[6, 5]
[5, 1]
\$\endgroup\$
2
\$\begingroup\$

Haskell, 76 70 bytes

 (x#y)f=until(<[10])(\[s,i]->[foldr(f.read.pure)0$show s,i+1])[f x y,1]

Returns a two element list with the result and number of steps. Works for arbitrary large numbers. Usage example: (351#14568)(+) -> [6,3].

Edit: Thanks to @BlackCap for 6 bytes.

\$\endgroup\$
1
  • \$\begingroup\$ You can replace (-48+).fromEnum with read.pure \$\endgroup\$
    – BlackCap
    Commented Sep 14, 2016 at 22:12
2
\$\begingroup\$

R, 91 bytes

Using @Vlo's code, which makes use of @plannapus's splitter, and some ideas I generated while golfing @Frédéric's answer, this is the shortest R answer yet. (An unusually large number of R answers here today...)

function(A,F,B){x=F(A,B);while(x>9){m=nchar(x);x=F(x%%10^(1:m)%/%10^(1:m-1));T=T+1};c(x,T)}

Crucially, this requires that the input for the operator be either sum for (+) or prod for (*). Under the rules of the challenge, this seems to be okay.

With indentation:

function(A,F,B){
  x=F(A,B);
  while(x>9){
    m=nchar(x);
    x=F(x%%10^(1:m)%/%10^(1:m-1));
    T=T+1
  };
  c(x,T)
}

Main differences from @Vlo's answer are:

  1. Instead of using Reduce, we rely on the input argument being a function, and just call it explicitly. (Yay for functions being first-class objects!)
  2. Instead of initializing a new variable as our counter, we abuse R's builtins and use T, which evaluates to TRUE (aka 1), but since it's not a reserved variable we can modify it. Thus T+T is 2. So we use that as our counter.
  3. Instead of cating the output, we just return it as a vector with c. As well as saving two bytes, the fact that the output is forced into a vector ensures that T is of class numeric. If we use cat, and T hasn't been incremented, then we get erroneous output like 1 TRUE.
\$\endgroup\$
4
  • \$\begingroup\$ you can restructure the while loop as follows, changing F to be something else to avoid name conflicts: function(A,O,B){x=O(A,B);while({F=F+1;x>9})x=O(x%/%10^(1:nchar(x)-1)%%10;c(x,F)}}. It's amazing how many R golfing tricks we've come up with in the last few years :) \$\endgroup\$
    – Giuseppe
    Commented Apr 11, 2018 at 18:08
  • \$\begingroup\$ @Giuseppe Nice restructuring! I can't find the meta consensus at the moment, but I'm reasonably confident that using the T and F counter trick within a function is actually invalid, as it means that the function can only be called once. So this answer (and several of my others!) are invalid, unless there's an explicit rm(T) at the end. I'm gonna keep looking for that meta post so I can be sure I didn't just dream it up. \$\endgroup\$
    – rturnbull
    Commented Apr 11, 2018 at 19:46
  • \$\begingroup\$ I believe that the T and F trick is perfectly valid as long as you don't modify T or F in the global environment. for instance, f=function(){T=T+1;T} consistently returns 2. I think this is the meta post to which you refer. \$\endgroup\$
    – Giuseppe
    Commented Apr 11, 2018 at 19:51
  • \$\begingroup\$ @Giuseppe Ah yes, you're right on both counts. Thanks! \$\endgroup\$
    – rturnbull
    Commented Apr 11, 2018 at 19:57
1
\$\begingroup\$

Ruby, 55 bytes

Recursive call. Used to be very different from @edc65's JavaScript answer but as I optimized it eventually became a direct port developed almost independently from their answer, minus one final optimization involving checking the eval'ed result instead of the length of the list of operands being passed in, which allowed me to surpass their byte count.

Input is a string representing the operator, and an array containing the operands.

Try it online.

f=->o,x,i=1{y=eval x*o;y>9?f[o,y.to_s.chars,i+1]:[y,i]}
\$\endgroup\$
2
  • \$\begingroup\$ The result is correct, but the number of steps required to obtain a single digit value is incorrect. Could you rectify your code? \$\endgroup\$ Commented Aug 25, 2016 at 1:24
  • \$\begingroup\$ @Anastasiya-Romanova秀 ah, you're right. My old logic required it to start from i=0 and I sort of forgot when refactoring. \$\endgroup\$
    – Value Ink
    Commented Aug 25, 2016 at 6:01
1
\$\begingroup\$

Perl, 38 bytes

Includes +2 for -ap

Run with the input on STDIN and spaces around the operator:

amath.pl <<< "12 + 123"
amath.pl <<< "12 * 123"

The output is digit and steps separated by +A

amath.pl:

#!/usr/bin/perl -ap
1while++$\,$_=eval."+A",s/\B/$F[1]/g

If outputting the steps in unary is ok this 35 byte version works better:

#!/usr/bin/perl -lap
1while$\.=1,$_=eval,s/\B/$F[1]/g
\$\endgroup\$
0
1
\$\begingroup\$

Mathematica, 105 94 bytes

Code.

{x,y}=(c=0;f//.a_:>(c++;t=o@@IntegerDigits@a);{t,c})&/.{{f->#1+#2,o->Plus},{f->#1#2,o->Times}}

Usage.

x[81, 31]
(* {4, 2} *)

x[351, 14568]
(* {6, 3} *)

y[21, 111]
(* {8, 3} *)

y[136, 2356]
(* {0, 2} *)

Explanation.

The two functions x (for (+)) and y (for (*)) are created at the same time by replacing the parameters f and o in

(c = 0;
 f //. a_ :> (c++; t = o@@ IntegerDigits@a);
 {t, c}
)&

with their appropriate values. For x, f becomes #1 + #2 and o becomes Plus; for y, they respectively become #1 #2 and Times. Rewriting the function x for the last part of the explanation:

x = (
  c = 0;
  #1 + #2 //. a_ :> (c++; t = Plus@@IntegerDigits@a); 
  {t, c}
) &;

(* The symbol //. stands for ReplaceRepeated. 
   The rule a_ :> (c++; t = Plus@@IntegerDigits@a) is applied until the result no longer 
changed. Specifically, the rule increments the counter of 1 at each step (this is c++), 
then takes the sum of the digits of the previous result (this is Plus@@IntegerDigits@a). 
The rule stops to apply when the variable t is less than 10. We return the final result and 
the number of steps with {t, c}. *)
\$\endgroup\$
1
\$\begingroup\$

Java 7, 203 195 192 bytes

int c=1;String c(long a,long b,int o){return p(((o<1?a+b:a*b)+"",o)+","+c;}long p(String n,int o){long x=o,q;for(String s:n.split("")){q=new Long(s);x=o<1?x+q:x*q}c++;return x<10?x:p(x+"",o);}

It uses long (maximum value of 263-1). If it would use int instead (maximum value of 231-1) it would only be 1 byte less (191 bytes):

int c=1;String c(int a,int b,int o){return p(((o<1?a+b:a*b)+"",o)+","+c;}int p(String n,int o){int x=o,q;for(String s:n.split("")){q=new Integer(s);x=o<1?x+q:x*q}c++;return x<10?x:p(x+"",o);}

It can most likely be golfed a bit more. Having to print the steps as well as the answer for both operators takes some bytes, though..
Uses 0 (for (+)) and 1 (for (*)).

Ungolfed & test code:

Try it here.

class Main{
  static int c = 1;
  static String c(long a, long b, int o){
    return p((o < 1 ? a+b : a*b) + "", o) + "," + c;
  }

  static long p(String n, int o){
    long x = o,
         q;
    for(String s : n.split("")){
      q = new Long(s);
      x = o < 1
           ? x + q
           : x * q;
    }
    c++;
    return x < 10
            ? x
            : p(x+"", o);
  }

  public static void main(String[] a){
    System.out.println(c(81, 31, true));
    c = 1;
    System.out.println(c(351, 14568, true));
    c = 1;
    System.out.println(c(21, 111, false));
    c = 1;
    System.out.println(c(136, 2356, false));
  }
}

Output:

4,2
6,3
8,3
0,2
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.