28
\$\begingroup\$

Implement a simple integer operation scriptable calculator.

Concept

The accumulator starts at 0 and has operations performed on it. At the end of the program output the value of the accumulator.

Operations:

  • + adds 1 to the accumulator
  • - subtracts 1 from the accumulator
  • * multiplies the accumulator by 2
  • / divides the accumulator by 2

Sample script

The input ++**--/ should give the output 3.

Example implementation

def calc(s)
    i = 0
    s.chars.each do |o|
        case o
            when '+'
                i += 1
            when '-'
                i -= 1
            when '*'
                i *= 2
            when '/'
                i /= 2
        end
    end
    return i
end

Rules

  • This is , so lowest answer in bytes wins, but is not selected.
  • Creative implementations are encouraged.
  • Standard loopholes are prohibited.
  • You get the program via stdin or arguments, and you can output the answer via return value or stdout.
  • Have fun.
  • Division truncates down because it is integer division.
  • The program -/ returns -1.

Test cases

*///*-*+-+
-1
/*+/*+++/*///*/+-+//*+-+-/----*-*-+++*+**+/*--///+*-/+//*//-+++--++/-**--/+--/*-/+*//*+-*-*/*+*+/+*-
-17 
+++-+--/-*/---++/-+*-//+/++-*--+*+/*/*/++--++-+//++--*/***-*+++--+-*//-*/+*/+-*++**+--*/*//-*--**-/-*+**-/*-**/*+*-*/--+/+/+//-+*/---///+**////-*//+-+-/+--/**///*+//+++/+*++**++//**+**+-*/+/*/*++-/+**+--+*++++/-*-/*+--/++*/-++/-**++++/-/+/--*/-/+---**//*///-//*+-*----+//--/-/+*/-+++-+*-*+*+-/-//*-//+/*-+//+/+/*-/-/+//+**/-****/-**-//+/+-+/*-+*++*/-/++*/-//*--+*--/-+-+/+/**/-***+/-/++-++*+*-+*+*-+-//+/-++*+/*//*-+/+*/-+/-/*/-/-+*+**/*//*+/+---+*+++*+/+-**/-+-/+*---/-*+/-++*//*/-+-*+--**/-////*/--/*--//-**/*++*+/*+/-+/--**/*-+*+/+-*+*+--*///+-++/+//+*/-+/**--//*/+++/*+*////+-*-//--*+/*/-+**/*//+*+-//+--+*-+/-**-*/+//*+---*+//*/+**/*--/--+/*-*+*++--*+//+*+-++--+-*-*-+--**+/+*-/+*+-/---+-*+-+-/++/+*///*/*-+-*//-+-++/++/*/-++/**--+-////-//+/*//+**/*+-+/+/+///*+*///*-/+/*/-//-*-**//-/-+--+/-*--+-++**++//*--/*++--*-/-///-+/+//--+*//-**-/*-*/+*/-*-*//--++*//-*/++//+/-++-+-*/*-+++**-/-*++++**+-+++-+-***-+//+-/**-+/*+****-*+++*/-*-/***/-/*+/*****++*+/-/-**-+-*-*-++**/*+-/*-+*++-/+/-++*-/*-****-*
18773342
\$\endgroup\$
  • 2
    \$\begingroup\$ So... it's not strictly integer, since / can yield non-integers. \$\endgroup\$ – Conor O'Brien Aug 28 '16 at 22:52
  • 2
    \$\begingroup\$ Then you should specify this explicitly. \$\endgroup\$ – Conor O'Brien Aug 28 '16 at 22:55
  • 5
    \$\begingroup\$ What should -/ return? \$\endgroup\$ – Dennis Aug 28 '16 at 23:32
  • 4
    \$\begingroup\$ I can't help but notice that the snippet of code featured on the home page of rust-lang solves this challenge. \$\endgroup\$ – Zwei Aug 29 '16 at 3:23
  • 4
    \$\begingroup\$ Please add more test cases. \$\endgroup\$ – Martin Ender Aug 29 '16 at 7:38

40 Answers 40

1
\$\begingroup\$

Ruby, 37 bytes

#!ruby -n
gsub(/./){eval"$.=$./2*2#$&2"}
p$./2

The shebang counts as 1 byte. This program uses xnor's creative approach. We avoid the need to initialise an accumulator variable by using $.. As it has a value of 1 after the input is read, we have to clear the LSB before applying each operator. This also requires changing &-2 to /2*2 for the correct precedence.

\$\endgroup\$
1
\$\begingroup\$

Java 7, 73 bytes

int c(char[]i){int r=0;for(int c:i)r=c<43?r*2:c<46?r+44-c:r>>1;return r;}

Shamelessly stolen from @Scepheo's amazing C# answer and implemented in Java 7.

Ungolfed & test cases:

Try it here.

class M{
  static int c(char[] i){
    int r = 0;
    for(int c : i) {
      r = c < 43
           ? r * 2
           : c < 46
              ? r+44 - c
              : r >> 1;
    }
    return r;
  }

  public static void main(String[] a){
    System.out.println(c("*///*-*+-+".toCharArray()));
    System.out.println(c("/*+/*+++/*///*/+-+//*+-+-/----*-*-+++*+**+/*--///+*-/+//*//-+++--++/-**--/+--/*-/+*//*+-*-*/*+*+/+*-".toCharArray()));
    System.out.println(c("+++-+--/-*/---++/-+*-//+/++-*--+*+/*/*/++--++-+//++--*/***-*+++--+-*//-*/+*/+-*++**+--*/*//-*--**-/-*+**-/*-**/*+*-*/--+/+/+//-+*/---///+**////-*//+-+-/+--/**///*+//+++/+*++**++//**+**+-*/+/*/*++-/+**+--+*++++/-*-/*+--/++*/-++/-**++++/-/+/--*/-/+---**//*///-//*+-*----+//--/-/+*/-+++-+*-*+*+-/-//*-//+/*-+//+/+/*-/-/+//+**/-****/-**-//+/+-+/*-+*++*/-/++*/-//*--+*--/-+-+/+/**/-***+/-/++-++*+*-+*+*-+-//+/-++*+/*//*-+/+*/-+/-/*/-/-+*+**/*//*+/+---+*+++*+/+-**/-+-/+*---/-*+/-++*//*/-+-*+--**/-////*/--/*--//-**/*++*+/*+/-+/--**/*-+*+/+-*+*+--*///+-++/+//+*/-+/**--//*/+++/*+*////+-*-//--*+/*/-+**/*//+*+-//+--+*-+/-**-*/+//*+---*+//*/+**/*--/--+/*-*+*++--*+//+*+-++--+-*-*-+--**+/+*-/+*+-/---+-*+-+-/++/+*///*/*-+-*//-+-++/++/*/-++/**--+-////-//+/*//+**/*+-+/+/+///*+*///*-/+/*/-//-*-**//-/-+--+/-*--+-++**++//*--/*++--*-/-///-+/+//--+*//-**-/*-*/+*/-*-*//--++*//-*/++//+/-++-+-*/*-+++**-/-*++++**+-+++-+-***-+//+-/**-+/*+****-*+++*/-*-/***/-/*+/*****++*+/-/-**-+-*-*-++**/*+-/*-+*++-/+/-++*-/*-****-*".toCharArray()));
  }
}

Output:

-1
-17
18773342
\$\endgroup\$
1
\$\begingroup\$

PHP, 146 138, 133, 131 bytes

$a=$_POST['s'];$i=0;while($a){$c=substr($a,0,1);$i=$c=='+'?$i+=1:($c=='-'?$i-1:($c=='*'?$i*2:round($i/2)));$a=substr($a,1);}echo$i;
  1. Takes argument from $_POST['s'].
  2. Uses ternary operator as "if's".
  3. Takes one character at a time, parse that char in operation, then continue reading next char
  4. EDIT 1: Shortened "while(strlen($a))" to "while($a)"
  5. EDIT 2: Removed some useless paranthesis
  6. EDIT 3. Removed extra space after last "echo"
\$\endgroup\$
  • \$\begingroup\$ I think with even PHP 5.5 having reached EOL it's safe to say that nobody SHOULD use PHP 4 anymore, so the "5+" is not necessary, imho. \$\endgroup\$ – YetiCGN Aug 29 '16 at 13:28
  • \$\begingroup\$ That is ok. For some scripts, it is important to show PHP version, maybe here it's not the case. Thanks, however. \$\endgroup\$ – Florin Chis Aug 29 '16 at 13:32
  • \$\begingroup\$ Yes, but if they start including the leaderboard snippet then your entry will be the top entry for the language "PHP 5+" while another one's entry will be leading "PHP 5.6" and maybe somebody else with worse score posts for "PHP 5.6.13 and up" ... You see my point? :-) \$\endgroup\$ – YetiCGN Aug 29 '16 at 13:34
  • \$\begingroup\$ That is correct. Thanks, again \$\endgroup\$ – Florin Chis Aug 29 '16 at 13:36
  • \$\begingroup\$ You can change $_POST['s'] to $_GET[s], which is bad practice but saves you 2 bytes.You might also try to remove the bracketrs of the while (-2) if you add a newline before the echo (+1) Not 100% sure about that. \$\endgroup\$ – Martijn Aug 29 '16 at 20:02
1
\$\begingroup\$

ARM Machine Code, 30 bytes

Hex Dump (little endian):

2000 f811 2b01 b14a 2a2a bf08 0040 d0f8 2a2e bf3a 3a2c 1a80 1040 e7f2 4770

This is a function that takes in a string, and returns the accumulated result. In C, the function would be declared int sioc(int dummy, char* string) where the dummy argument is ignored. Tested on the Raspberry Pi 3. No libraries or system calls are used.

Ungolfed assembly:

.syntax unified
.text
.global sioc
.thumb_func
sioc:
    @Input: r0 - dummy argument
    @r1 - string of operations
    @Output: r0 - result of those operations
    movs r0,#0 @Initialize accumulator to 0
    loop:
        ldrb r2,[r1],#1 @r2=*r1++
        cbz r2,end @If (r2==0), goto end
    mul:
        cmp r2,#42
        it eq @if r2==42
        lsleq r0,r0,#1 @r0<<=1
        beq loop @continue
    addsub: @else
        cmp r2,#46
        itte lo @If r2<46, then r2 is either + or -
        sublo r2,r2,#44
        sublo r0,r0,r2 @Add 1 if r2 is +, subtract 1 if r0 is -
        asrhs r0,r0,#1 @else arithmatically shift right by 1
        b loop @while (true)
    end:
        bx lr

Testing script (also assembly):

.syntax unified
.text
.global main
.thumb_func
main:
    ldr r1,[r1,#4] @r0=argv[1]
    bl sioc
    mov r1,r0
    adr r0,msg
    bl printf
    movs r7,#1
    swi #0
.balign 4
msg:
    .asciz "%d\n"
\$\endgroup\$
1
\$\begingroup\$

Java 8, 56 bytes

s->s.chars().reduce(0,(r,c)->c<43?r*2:c<46?r+44-c:r>>1);
\$\endgroup\$
1
\$\begingroup\$

Haskell - 70 bytes

f x=foldl1(flip(.))[[(*2),succ,id,pred,id,(`div`2)]!!(ord n-42)|n<-x]0

64 if I may take the input in RPN:

f x=foldl1(.)[[(*2),succ,id,pred,id,(`div`2)]!!(ord n-42)|n<-x]0


In addition to + - * / my implementation also support , and ., both of which does nothing. It crashes for any other input.

\$\endgroup\$
1
\$\begingroup\$

Python3, 98 85 74 bytes

C=lambda s,n:s and C(s[1:],{3:n+1,5:n-1,2:n*2,7:n/2}[ord(s[0])%10])or n//1

A recursive solution that loops over the string and takes the (modulo 10) from the ASCII value of the iterated character and treats the carried number accordingly. The dictionary keys are the last digits of the possible ASCII values that may occur (+, -, *, /) and the values are the corresponding results for the symbol.We pass the input string s forward by taking everything onward from the next character with s[1:] (thanks to @Destructible Watermelon!).

Could be shortened even more, by picking the actions from a list and moduloing to keep the index in range, but that feels like plagiarism at this point, so unless I find my own method for that, it won't happen.

Called like: C("+-+**+/",0) ==> 2.0

(Ps. Is it allowed to return -1.0 from input -/?)

\$\endgroup\$
1
\$\begingroup\$

GolfScript - 45 bytes

{1+}:"+";{1-}:"-";{2/}:"/";{2*}:"*";0\1/{`~}/

Explanation

{1+}:"+";  # Creates aliases for operators
{1-}:"-";
{2/}:"/";
{2*}:"*";
0\1/       # Pushes 0 and splits the string in bytes
{`~}/      # Executes each character
\$\endgroup\$
0
\$\begingroup\$

TSQL, 115 bytes

After some golfing I was finally able to replace -IIF(@<0,@,@+1)/2 with (@+ABS(@%2))/-2 saving 2 bytes.

Golfed:

DECLARE @i varchar(max)='*///*-*+-+'
,@ INT=0WHILE @i>''SELECT @+=CHOOSE(CHARINDEX(LEFT(@i,1),'+-*/'),1,-1,@,(@+ABS(@%2))/-2),@i=STUFF(@i,1,1,'')PRINT @

Ungolfed:

DECLARE @i varchar(max)='*///*-*+-+'

,@ INT=0
WHILE @i>''
  SELECT @+=CHOOSE(CHARINDEX(LEFT(@i,1),'+-*/'),1,-1,@,(@+ABS(@%2))/-2),
  @i=STUFF(@i,1,1,'')
PRINT @

Fiddle

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

Racket 116 bytes

(λ(s)(let((l(string->list s))(a 0))(for((i l))(set! a(match i[#\+(+ a 1)][#\-(- a 1)][#\*(* a 2)][#\/(/ a 2)])))a))

Ungolfed version:

(define f
  (lambda(s)
    (let ((l (string->list s))
          (a 0))
      (for ((i l))
        (set! a (match i
                  [#\+ (+ a 1)]
                  [#\- (- a 1)]
                  [#\* (* a 2)]
                  [#\/ (/ a 2)]
                )))
      a)))

Testing:

(f "++**--/")

3
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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