# Calculate a tip

You and a friend walk into a bar. The bartender treats you well, so you decide to tip him. So you pull out your trusty pocket computer and write a quick program to calculate a tip for you since it has no built in calculator. But wait! Your operator keys are broken! Your task is to calculate a 20% tip for any given input amount. The test inputs will be in the form of xx.xx e.g. 20.96. Here are the rules:

• No use of the following in mathematical form operators: + - * / % (Thanks Wally West)
• No use of built in percent functions or APIs
• No accessing the network
• No use of eval or similar
• No Windows Calculator (yes people have answered with it before)
• No built in tip functions (Not that any language would have one)

Output should be rounded up to two decimal places.

Score is based on length in bytes.

-20% if your program can accept any tip amount. Input for amount will be given in the form of xx e.g. 35 not 0.35

• @mniip: A tip is a bizarre extra amount of money you're expected to pay at a restaurant that isn't part of the official price. I don't know if they do that in Russia. – user2357112 supports Monica Mar 12 '14 at 7:36
• Oh, that new generation... I would rather use paper and pen if I can't mentally divide a number by 5. – VisioN Mar 12 '14 at 8:45
• @VisioN Note: dividing by five is equivalent to dividing by 10 then multiplying by 2, and both should be very easy mental operations. – user12205 Mar 12 '14 at 9:05
• Can someone clarify the rules: Is using the forbidden operations allowed if you don't use those operators? Is multiplication allowed if you don't use *? – Ypnypn Mar 12 '14 at 20:44
• @TheDoctor is it really a duplicate though? Because it's not adding. – Milo Mar 12 '14 at 21:50

## Javascript 81

EDIT : The result is now a real rounding, not truncated.

Do not use ANY math here, just string manipulation and bitwise operators.
All the + char are string concatenation, or string to float conversion.
Works for any xx.xx input and outputs in (x)x.xx format

s='00'+(prompt().replace('.','')<<1);(+s.replace(/(.*)(...)/,'$1.$2')).toFixed(2)


Trick explained : 20% is divided by 10 and multiplied by 2.

• Make a division by 10 by moving the dot to the left (string manipulation)
• Multiply each part by 2 by moving bits to the left (bitwise operation)
• When input is 99.99, this returns 19.998, so it's not "rounded up to two decimal places" as per the OP. – Geobits Mar 12 '14 at 18:51
• Umm this is a long solution, but it has 12 upvotes. What is going on with code-golf's voting? – Justin Mar 13 '14 at 5:16
• @Quincunx Yes you are right its not popularity contest! – Mukul Kumar Mar 13 '14 at 5:48
• Since it is a code-golf, I will probably not win, but this doesnt mean that people can't like my solution... Often, code-golf winners are not those with the most upvotes. – Michael M. Mar 13 '14 at 6:56
• @n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳, absolutly ! Thank you for pointing this out. Fixed now :) – Michael M. Mar 13 '14 at 12:54

# J (9 characters)

^.(^.2)^~ 32

• ...and I do not speak J. What does it say? – CousinCocaine Mar 13 '14 at 13:22
• It says: compute 32 raised to power log(2); usually, exponent is at the right of ^ but here ~ indicates the order should be reversed; (^.2)is log(.2), and the initial ^. which is executed last is the logarithm of everything compute dpreviously: thus log(32^log(.2)) – Thomas Baruchel Mar 13 '14 at 13:29

# Pure bash, 50 43 chars

Pretty sure this'll be beat, but here's a start:

a=$[10#${1/.}<<1]
echo ${a%???}.${a: -3:2}


• / is not a division operator here, it is part of a pattern substitution parameter expansion
• % is not a modulo operator here, it is part of a parameter expansion
• - is not a subtraction operator here, it is a negation, which was allowed as per the comments

Output:

$./20pct.sh 0.96 .19$ ./20pct.sh 20.96
4.19
$./20pct.sh 1020.96 204.19$

• I think I see a forward slash in there. – Milo Mar 12 '14 at 6:22
• @Milo that / is part of a bash parameter expansion and not a division operator. Allowed or not? – Digital Trauma Mar 12 '14 at 6:24
• I would allow it, it's not a mathematical operator in this case... – WallyWest Mar 12 '14 at 6:25
• -3 acts as a negation not a subtraction... @Milo, you need to account for negation and other ways that these operators can be used aside from their mathematical equivalents... for example + can be used as a concatenator in JavaScript... Can I make a suggestion? Change "No use of the following operators: + - * / %" to "No use of the following operators in their mathematical form: + - * / %" – WallyWest Mar 12 '14 at 6:30
• @WallyWest To play devil's advocate, the negation here is still a mathematical operator. Perhaps "No use of the following operators in their non-unary mathematical form: + - * / %" ;-) – Digital Trauma Mar 12 '14 at 6:33

## Python 98*0.8=78.4

d=len('X'*int("{}{:>02}".format(*(raw_input()+".0").split('.')))*2);print'%s.%s'%(d[:-3],d[-3:])


## Python 74 (without bonus)

d=len('X'*int(raw_input().replace('.',''))*2);print'%s.%s'%(d[:-3],d[-3:])


Note

• + is used for string concatenation
• * used to create copies of string

Ungolfed

def tip():
amount = raw_input()
#Add an extra decimal point so that we can accept integer
#amount
amount += ".0"
#Split the integer and decimal part
whole, frac = amount.split('.')
#Multiply amount by 100 :-)
amount = "{}{:>02}".format(whole, frac)
#Create amount copies of a character
st = 'X'*amount
#Double it
st *= 2
#Calculate the Length
d = len(st)
#Display the result as 3 decimal fraction
print'%s.%s'%(d[:-3],d[-3:])


Note

In spirit of the question, I believe the following solution though follows all rules of the question is an abuse

## Python 41

print __import__("operator")(input(),0.2)


Finally

If you insist that the mathematical symbols are forbidden, her is a 90 character solution

## Python 90 (without any mathematical symbol)

print' '.join(str(int(raw_input().replace(".",""))<<1)).replace(' ','.',1).replace(' ','')

• As already said, * and + are broken KEYS (whatever you use them for). – Thomas Baruchel Mar 12 '14 at 9:58
• @ברוכאל: No use of the following in mathematical form operators: + - * / % (Thanks Wally West). In other words, the question needs to be rephrased. And I have not used them in mathematical form – Abhijit Mar 12 '14 at 10:00
• OK, but in that case, the downvote of the APL solution was'nt really fair, since no other solution has been downvoted for that reason. – Thomas Baruchel Mar 12 '14 at 10:01
• Your answer is going to have problem with miniscule amount of money, e.g. 0.05. – n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 13 '14 at 11:37
• You can use input (backticks included) instead of raw_input. – nyuszika7h Jun 12 '14 at 21:12

# APL (9 characters, new code with 7 characters, fixed with 13 characters)

Compute 20% of the given amount.

{⍟⍵*⍨*.2} 32


In APL * is the exponential operator.

Try it online.

But why use a function for that? See this new version:

⍟(*.2)* 32


Try it online.

Please, before downvoting, the * is not forbidden as a KEY and it doesn't mean multiplication here.

OK, here is the version rounding to 2 decimals (Dyalog APL):

⎕PP←2⋄⍟(*.2)* 32.01

• Exponentiation is still a mathematical operation, and * is disallowed in any mathematical form as per the rules of the challenge. – Tony Ellis Mar 12 '14 at 9:26
• Exponentiation is not fobidden here and other solutions actually use it, but you are right concerning the fact that * is forbidden as a key and not as its mathematical meaning. – Thomas Baruchel Mar 12 '14 at 9:36
• @Tony H. Please, could you remove your downvote, since obviously all comments in other solutions seem to finally accept such KEYS as long as they aren't used for the forbidden mathematical operations in the initial list. – Thomas Baruchel Mar 12 '14 at 10:03
• @ברוכאל It's my understanding that usage of an asterisk in any way that pertains to a mathematical meaning is forbidden, that includes exponentiation. Every other answer thus-far that uses exponents is in a language that uses the caret (^) for such an operator, or a function call is used. There is no specification by the OP that * is disallowed only if it's used in the context of multiplication. I suspect it would be helpful if OP were to rule on this, to settle which one of us is misinterpreting the rules of the challenge and to clear up the confusion. – Tony Ellis Mar 12 '14 at 14:14
• Perhaps × and ÷ are allowed, those are not listed. – marinus Mar 12 '14 at 17:05

# R, 30 27 36 34

Updated to round to 2 decimal places

Saved 2 characters thanks to plannapus

Creates a vector from 0 to x and takes the 2nd element.

a=function(x)round(seq(0,x,l=6)[2],2)


Example:

> a(20.36)
[1] 4.07


## Further explanation:

seq(0,x,len=6)


creates a vector of length 6 from 0 to the input value x, with the values in between equally spaced.

> seq(0,5,len=6)
[1] 0 1 2 3 4 5


The first value is then 0%, the second 20%, third 40%, etc.

• Wait... what ? Please give more details of how it works for those (like me) who don't know R. – Michael M. Mar 12 '14 at 18:50
• @Michael updated my answer to explain the code – Rift Mar 12 '14 at 20:27
• Your solution doesn't do any rounding. – n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 13 '14 at 12:02
• @n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ you are right (but most solutions aren't rounding anything). 9 extra characters would do "normal" rounding. Only rounding up would be way harder... – Rift Mar 13 '14 at 13:11
• @Rift: I have tested several answers (mostly Python, JS and Perl, since they are easily available) and most of them do rounding. None of those I have tested rounds up, though. – n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 13 '14 at 13:20

# dc + sed + pipes (44 characters)

My third answer (one APL, one J, and now one with the old and venerable dc).

42
8.400
$dc -e 5o?.0+p|sed 's/$$.$$\./.\1/'|dc -e 5i?p 20.96 4.1920  • The .0+ idea is great; I voted up for your solution inspired by mine, but some may tell you are using addition; maybe some workaround? I tried dc -e 9k5o?v2^p but it is 2 characters more. – Thomas Baruchel Mar 12 '14 at 17:42 • @ברוכאל I didn't realize that the + even in this context might qualify as addition. – devnull Mar 12 '14 at 18:10 • @ברוכאל I'll delete this one. Request you to modify your so that it could handle floats and qualify for -20%! – devnull Mar 12 '14 at 18:12 # Mathematica, 19 Log[(E^.2)^Input[]]  No use of the mathematical operators of +, -, *, /, or %. Uses properties of logarithms to calculate the answer; when you simplify the expression, you get .2*Input[] With the bonus (30 * 0.8 = 24): Log[((E^.01)^Input[])^Input[]]  Input the percentage first, then the amount. When you simplify the expression, you get Input[]*Input[]*.01. Thanks to ברוכאל for help with shortening the code. • Are you really sure it can't be simplified? To me Log[E^2] or Log[E^Input[]] can be written more shortly. Even 10^-1 can be written .01 (though I don't use Mathematica but I am pretty sure it can). The whole expression (E^10^-1)^Log[E^2] seems to be something like E^.2, isn't it? – Thomas Baruchel Mar 12 '14 at 8:20 # TI-89 Basic - 39 * 0.8 = 31.2 Input y:Input x:Disp ln(((e^y)^.01)^x))  Works by inputting the two numbers, then using the logarithm properties to compute x * y / 100. If I can assume input from placement in global variables x and y, then this is much shorter, for a score of 17 * 0.8 = 13.6: ln(((e^y)^.01)^x)  Without bonus (12): ln((e^.2)^x)  But if it needs to be wrapped in a function, then this works (38 chars, for 30.4): :f(x,y):Func:ln(((e^y)^.01)^x):EndFunc  • Please, see my comments to your other solution (in Mathematica); this code can really be simplified much. – Thomas Baruchel Mar 12 '14 at 8:24 • Input x,y ??? Works in 83/84. – Timtech Mar 12 '14 at 11:09 • @Timtech Doesn't work in 89, but maybe I can do something like Input{x,y} (does 83/84 have ln?) – Justin Mar 12 '14 at 18:51 • @Quincunx Yes, see my new answer. – Timtech Mar 12 '14 at 20:20 • žr¹msmžr.n - shameless port of this code into 05AB1E. – Magic Octopus Urn Apr 11 '17 at 19:21 # PHP 107 *.8 = 85.6 can't really run for code-golf with PHP, but at least I can operate on strings. accepts both numbers as command-line arguments. <? @$r=strrev;unset($argv[0]);echo$r(substr_replace($r(str_replace('.','',array_product($argv)))),'.',2,0);


had to reverse it twice since I can't use -2 :(

# Python, 81 80 89 characters

a,b=map(str,raw_input().split('.'));c=str(int(a+b)<<1).zfill(4);print c[:-3]+'.'+c[-3:-1]


Explanation

x = raw_input()       # say 20.96
a , b = x.split('.')  # a = 20 , b = 96
c = a + b             # c = '2096'      # string concatenation , multiplying by 100
d = int(c)<<1         # multiply by 2 by bitshift left , c = 4096
e = str(d).zfill(4)   # zfill pads 0's making the string
# atleast 4 chars which is required
# for decimal notation next

#     divide by 1000 (4) + . (4.) + fraction rounded to 2 decimals (4.09)
print        e[:-3]      +   '.'  +              e[-3:-1]


Technically, this is cheating as it truncates to two decimals rather than rounding it but I can argue that it rounds down(Better for you, less tip).

• I think you can do [-3:] instead of [-3:-1] – Justin Mar 12 '14 at 18:53
• @Quincunx Can't , the -1 is to truncate to two decimals. – user80551 Mar 13 '14 at 3:42
• @n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Yep, fixed it. – user80551 Mar 13 '14 at 11:36

# JavaScript 251 (forced restriction: no +, -, *, ? or % in any manner)

While I know this won't win, I figured I'd try to get brownie points through taking a very strict approach and not even think about using the restricted operators in any shape or form... as a result, I came up with this beauty...

A=(x,y)=>{for(;x;)b=x^y,x=(a=x&y)<<1,y=b;return y};D=(x,y,i=x,j=0)=>{for(;i>=y;)i=A(i,A(~y,1)),j=A(j,1);return j};alert(parseFloat((x="00".concat(String(D(prompt().replace(".",""),5)))).substr(0,A(x.length,y=A(~2,1))).concat(".").concat(x.substr(y))))


I used bitwise operations to create the Add function A, and then started chaining up from there:

The integer division function D used a series of Negated Addition (subtraction in the form of A(x,A(~y,1) over a loop; the rest is string manipulation and concatenation so as to avoid using + concatenation operators...

The number must be provided in decimal form with two decimal places for this to work...

• Ah, it will now... though if I had to keep to the new rules, I had to expand on it... 251 bytes now... – WallyWest Mar 13 '14 at 12:38

## Perl, 50 60 bytes

$_=<>;s|\.||;$_<<=1;$_="00$_";m|\d{3}$|;printf'%.2f',"$.$&"  The input is expected at STDIN. It must contain the decimal separator with two decimal digits. The output is written to STDOUT. Update: The step $_<<=1 removes leading zeroes. Therefore m|\d{3}$| would not match for bills < 1. Therefore ten bytes $_="00$ were added, Now even 0.00 works. Examples: • Input: 20.96, output: 4.19 • Input: 12.34, output: 2.47 Ungolfed version: $_=<>;
s|\.||; # multiply by 100
$_ <<= 1; # multiply by 2$_="00$_"; m|\d{3}$|; # divide by 1000
printf '%.2f'," $.$&"


First the number is read from STDIN. Then the decimal dot is removed, that is multiplied with 100. Then the amount is doubled by a shifting operator. Then the decimal dot is reinserted and the result is printed and rounded to two decimal digits.

50 bytes, if bill ≥ 1:

If x.xx is greater or equal than 1.00, then 10 bytes can be removed:

$_=<>;s|\.||;$_<<=1;m|\d{3}$|;printf'%.2f',"$.$&"  • @n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳: Thanks, fixed now. – Heiko Oberdiek Mar 13 '14 at 13:57 # JavaScript (ES6) (Regex) 142 Regex is great and it can do many things. It can even do maths! a=('x'.repeat(prompt().replace('.', ''))+'xxxx').match(/^((x*)\2{99}(x{0,99}))\1{4}x{0,4}$/);c=a[3].length;alert(a[2].length+'.'+(c<10?'0'+c:c))


function tip(m) {
var a = s.match(/^((x*)\2{99}(x{0,99}))\1{4}x{0,4}$/); var c = a[3].length; if (c < 10) c = '0' + c; return a[2].length + '.' + c; }  The tip() function expects String argument, rather than Number. All instances of *, /, + are not related to math operations. • + is string concatenation in all instances it is used. • * is part of RegExp syntax • / is the delimiter of RegExp literal The input must use . as decimal point, and there must be 2 digits after decimal point. # Stack Snippet <button onclick = "a=('x'.repeat(prompt().replace('.', ''))+'xxxx').match(/^((x*)\2{99}(x{0,99}))\1{4}x{0,4}$/);c=a[3].length;alert(a[2].length+'.'+(c<10?'0'+c:c))">Try it out</button>
t y x=log $(^x)$(**0.01)\$ exp y
`