How does math work in Anastasiya's world?

44

4

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

Anastasiya-Romanova 秀

Posted 2016-08-24T09:12:09.587

Reputation: 1 673

The repeated addition part (digital root) is essentially a duplicate of http://codegolf.stackexchange.com/q/1128/194

– Peter Taylor – 2016-08-24T09:49:43.917

@PeterTaylor The addition part might be true, but there are additive and multiplicative persistence part here, so they're semi-related but not a dup, IMHO. – Anastasiya-Romanova 秀 – 2016-08-24T09:55:39.433

4Great first question! And I recognize the general rules format and sentences from my own Questions. ;) – Kevin Cruijssen – 2016-08-24T11:10:16.057

4@KevinCruijssen Yup. that's right. Since it has no copyright so I duplicate it without your permission. Hehehe :D – Anastasiya-Romanova 秀 – 2016-08-24T11:11:43.337

Related: Manhattan and Fuzzy-Logic.

– Adám – 2016-08-24T13:26:52.190

4@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. – Mindwin – 2016-08-24T14:42:08.897

Can the input to the function be (12, &[+], 123), where &[+] is short for &infix:< + > a reference to the infix numeric addition operator subroutine? – Brad Gilbert b2gills – 2016-08-24T15:11:08.607

1@BradGilbertb2gills Yes, of course. It's stated in the post by the way. Quote: "The format of the input is an arbitrary choice of the programmer". – Anastasiya-Romanova 秀 – 2016-08-24T15:43:27.177

Answers

11

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.

Adám

Posted 2016-08-24T09:12:09.587

Reputation: 37 779

Thanks for the answer, (+1). Can it handle large number inputs? – Anastasiya-Romanova 秀 – 2016-08-24T10:04:00.673

1If 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³⁴. – Adám – 2016-08-24T10:13:27.990

Hmm, even though it has full support, aren't +{n←0⋄n,⍺⍺{n+←1⋄⍺⍺/⍎¨⍕⍵}⍣=⍵⍺⍺⍨⍺} and ×{n←0⋄n,⍺⍺{n+←1⋄⍺⍺/⍎¨⍕⍵}⍣=⍵⍺⍺⍨⍺} still quite a few bytes? I'm confused about how this is 0 bytes.. :S – Kevin Cruijssen – 2016-08-24T14:16:15.170

3@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. – Adám – 2016-08-24T14:21:25.173

1@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. – Kevin Cruijssen – 2016-08-24T14:26:54.280

@KevinCruijssen in Pyke it would be 1 byte and in Python 2 it would be input(). – Blue – 2016-08-24T20:41:04.060

If I'm understanding this correctly, with the right golfing language, any task could be done with zero bytes. – Acccumulation – 2018-04-16T16:13:29.873

@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.

– Adám – 2018-04-16T16:29:45.310

8

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!

ThreeFx

Posted 2016-08-24T09:12:09.587

Reputation: 1 435

Thanks for the answer, (+1). Can it handle large number inputs? – Anastasiya-Romanova 秀 – 2016-08-24T10:04:38.300

4@Anastasiya-Romanova秀 Yes, it can handle numbers as big as your RAM since Haskell's Integer type is unbounded. – ThreeFx – 2016-08-24T10:28:51.670

8

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.

Blue

Posted 2016-08-24T09:12:09.587

Reputation: 26 661

1Nice! Can we get an explanation? – Emigna – 2016-08-24T09:57:00.110

Thanks for the answer, (+1). Can it handle large number inputs? – Anastasiya-Romanova 秀 – 2016-08-24T10:03:38.660

@Anastasiya-Romanova秀 it should be able to handle arbitrary numbers – Blue – 2016-08-24T10:06:57.030

I cannot test your code because the web is blocked since it's in violation of my parents' internet usage policy. T_T – Anastasiya-Romanova 秀 – 2016-08-24T10:10:25.760

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 – Anastasiya-Romanova 秀 – 2016-08-24T10:13:54.830

Hmm... I've no idea why it would be blocked... Image of output here

– Blue – 2016-08-24T10:16:50.703

8

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

edc65

Posted 2016-08-24T09:12:09.587

Reputation: 31 086

Thanks for the answer, (+1). Can it handle large number inputs? – Anastasiya-Romanova 秀 – 2016-08-24T10:45:11.617

1@Anastasiya-Romanova秀 up to the limit of javascript numeric format, 53 bits of precision (17 decimal digits) – edc65 – 2016-08-24T10:58:46.510

8

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.

Dennis

Posted 2016-08-24T09:12:09.587

Reputation: 196 637

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... – Dennis – 2016-08-25T01:54:28.447

"The format of the input is an arbitrary choice of the programmer" – Tobias Kienzler – 2016-08-25T11:48:45.050

...in which case I'd even go as far and consider passing operator.add or operator.mul respectively ;) – Tobias Kienzler – 2016-08-25T11:58:46.050

7

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 !

Frédéric

Posted 2016-08-24T09:12:09.587

Reputation: 2 059

Yes, please do add explanations since I love R! This is my second language after VBA. (+1) – Anastasiya-Romanova 秀 – 2016-08-24T10:21:06.533

1@Anastasiya-Romanova 秀 : Done ! – Frédéric – 2016-08-24T12:31:23.913

@plannapus : Really nice ! Thanks a lot ! – Frédéric – 2016-08-24T14:29:02.827

1@Frédéric nice use of strtoi! 4 more bytes are you have me beaten. – plannapus – 2016-08-26T09:01:14.470

@plannapus : I'm trying, I'm trying ! :D – Frédéric – 2016-08-26T10:16:01.953

It might be possible to overload Ops and save some bytes? That would cover + and * in one go, but the input has to be classed. – JDL – 2016-08-26T15:04:39.587

Can save some money with while(x>9) – Vlo – 2016-08-26T20:38:33.730

@Vlo : Brilliant ! – Frédéric – 2016-08-26T20:48:34.420

If you change the input to use 1 to represent (+) and 2 to represent (), then you can have switch(S,sum,prod), saving 4 bytes. I think this is acceptable as the specification says you can have input in whatever format you like. Additionally, prod() is equivalent to `(), so you can save another byte by having switch(S,sum,*`). – rturnbull – 2016-09-14T23:13:15.417

1Looks 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);. – rturnbull – 2016-09-14T23:24:36.670

Okay, one more, I promise. Since T is not a reserved variable name, it can be redefined at will, which means we can use it in place of i. So i=1; can be removed (since T is already TRUE which is the same as 1), and i=i+1; and c(i,x) replaced with T=T+1; and c(T,x), thus saving four bytes. Yes, it's a terrible abuse! – rturnbull – 2016-09-15T11:17:15.730

7

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.

FryAmTheEggman

Posted 2016-08-24T09:12:09.587

Reputation: 16 206

6

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

Emigna

Posted 2016-08-24T09:12:09.587

Reputation: 50 798

Thanks for the answer, (+1). Can it handle large number inputs? – Anastasiya-Romanova 秀 – 2016-08-24T10:03:17.633

@Anastasiya-Romanova秀 I don't see a reason why not. Do you have an example? – Emigna – 2016-08-24T10:04:04.410

Your program's been tested for that kind of inputs, so it perfects :) – Anastasiya-Romanova 秀 – 2016-08-24T10:07:28.670

6

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.

Dennis

Posted 2016-08-24T09:12:09.587

Reputation: 196 637

6

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

Ian Chew

Posted 2016-08-24T09:12:09.587

Reputation: 171

4

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...

Stewie Griffin

Posted 2016-08-24T09:12:09.587

Reputation: 43 471

4

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

Shaun Wild

Posted 2016-08-24T09:12:09.587

Reputation: 2 329

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..

– Kevin Cruijssen – 2016-08-24T12:11:17.120

@KevinCruijssen Ahh. That's boring.. I'll try fix that now. – Shaun Wild – 2016-08-24T12:14:39.360

Btw, you can golf your current answer a bit. m==0 can be m<1, and Integer.parseInt can be Integer.decode. – Kevin Cruijssen – 2016-08-24T12:14:46.063

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. – milk – 2016-08-25T01:59:24.297

@milk Well spotted. – Shaun Wild – 2016-08-25T08:15:27.400

Hmmm... I guess I unwittingly approved this by suggesting @todeale's edit include changes to the byte count in review. Please double the change carefully. – Linus – 2016-09-02T01:36:36.577

1Can we not change my posts in future? If you want to suggest an edit do so in the comments. – Shaun Wild – 2016-09-02T08:28:17.120

Comment by Todeale: "Changing (r + "").length() > 1 by r > 9 saved a few bytes. I'm sorry I couldn't comment because I don't have enough reputation." – Stewie Griffin – 2016-09-03T10:53:53.377

4

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

plannapus

Posted 2016-08-24T09:12:09.587

Reputation: 8 610

Quite unfortunate you came late with this answer, but you have my upvote. Thanks for creating this in R. – Anastasiya-Romanova 秀 – 2016-08-24T15:46:27.233

Why unfortunate? – plannapus – 2016-08-25T06:28:10.143

Because if you had come first, then you'd have got more upvotes – Anastasiya-Romanova 秀 – 2016-08-25T07:54:48.147

@Anastasiya-Romanova秀 Fair enough :) – plannapus – 2016-08-25T08:14:16.163

Bonus points for having f be both the function name and one of its arguments :) – JDL – 2016-08-26T15:16:29.240

I wrote a solution but it turned out to be 130+. The bottleneck was the strsplit part as a Reduce approach is more byte efficient than a switch solution. So by replacing the inefficient splitter with your splitter, we can golf it down even further. f=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)} `112 bytes – Vlo – 2016-08-26T19:01:58.747

@Vlo That's a cool and original solution (i never think of Reduce!), you should write it down as a new answer! – plannapus – 2016-08-26T20:13:14.963

3

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.

clismique

Posted 2016-08-24T09:12:09.587

Reputation: 6 600

Thanks for the answer, (+1). Can it handle large number inputs? – Anastasiya-Romanova 秀 – 2016-08-24T10:47:04.813

@Anastasiya-Romanova秀 Uhmmm... I'm fairly sure they can. Can you give me examples of large inputs? I'll try and calculate from those. – clismique – 2016-08-24T10:50:01.620

Maybe: 3218753647208435810122106*29349566754? – Anastasiya-Romanova 秀 – 2016-08-24T10:54:53.220

1@Anastasiya-Romanova秀 Yeah, it worked in ~0.5 seconds, didn't properly time it. – clismique – 2016-08-24T11:01:12.150

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. – Copper – 2016-08-24T11:14:17.507

You can also change [n,c] to n,c, [int(x) for x in list(n)] to map(int,list(n)), and "n=...a,b"+t+"b,..." to "n=...a,b%sb,..."%t. – Copper – 2016-08-24T11:18:09.957

Finally: while len(n)!=1 can be changed to while n[1:]. – Copper – 2016-08-24T11:22:13.310

@Copper You, sir, are a legend. Thanks for all the tips! – clismique – 2016-08-24T11:26:21.663

you can change ["+" in s] to ["+"in s], just like @Copper originally suggested (the space in front of in can be omitted).. – Graipher – 2016-08-25T06:44:46.823

3

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].

Lynn

Posted 2016-08-24T09:12:09.587

Reputation: 55 648

Thanks for the answer, but your program output doesn't contain the number of steps required part? Am I missing something here? – Anastasiya-Romanova 秀 – 2016-08-24T10:57:53.257

3

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.

Vlo

Posted 2016-08-24T09:12:09.587

Reputation: 806

R is fantastic because allowing us to shorten its function, something that's valuable in golfing. (+1) – Anastasiya-Romanova 秀 – 2016-08-26T20:40:12.650

3

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.

James B.

Posted 2016-08-24T09:12:09.587

Reputation: 51

This is very late, but you can reduces most of the spaces in there. – clismique – 2016-12-25T03:26:53.113

2

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.

nimi

Posted 2016-08-24T09:12:09.587

Reputation: 34 639

You can replace (-48+).fromEnum with read.pure – BlackCap – 2016-09-14T22:12:23.220

2

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)

Brad Gilbert b2gills

Posted 2016-08-24T09:12:09.587

Reputation: 12 713

2

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

TheBikingViking

Posted 2016-08-24T09:12:09.587

Reputation: 3 674

(+1) while waiting the explanation :) – Anastasiya-Romanova 秀 – 2016-08-25T01:25:24.093

2

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]

Roger Glover

Posted 2016-08-24T09:12:09.587

Reputation: 21

2

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.

rturnbull

Posted 2016-08-24T09:12:09.587

Reputation: 3 689

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 :) – Giuseppe – 2018-04-11T18:08:46.827

@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. – rturnbull – 2018-04-11T19:46:48.853

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.

– Giuseppe – 2018-04-11T19:51:31.693

@Giuseppe Ah yes, you're right on both counts. Thanks! – rturnbull – 2018-04-11T19:57:59.463

1

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

Kevin Cruijssen

Posted 2016-08-24T09:12:09.587

Reputation: 67 575

1

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}. *)

user48818

Posted 2016-08-24T09:12:09.587

Reputation:

1

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]}

Value Ink

Posted 2016-08-24T09:12:09.587

Reputation: 10 608

The result is correct, but the number of steps required to obtain a single digit value is incorrect. Could you rectify your code? – Anastasiya-Romanova 秀 – 2016-08-25T01:24:33.640

@Anastasiya-Romanova秀 ah, you're right. My old logic required it to start from i=0 and I sort of forgot when refactoring. – Value Ink – 2016-08-25T06:01:31.693

1

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

Ton Hospel

Posted 2016-08-24T09:12:09.587

Reputation: 14 114