Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

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

share|improve this question
4  
@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 Mar 12 at 7:36
5  
Oh, that new generation... I would rather use paper and pen if I can't mentally divide a number by 5. –  VisioN Mar 12 at 8:45
4  
@VisioN Note: dividing by five is equivalent to dividing by 10 then multiplying by 2, and both should be very easy mental operations. –  ace Mar 12 at 9:05
1  
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 at 20:44
2  
@TheDoctor is it really a duplicate though? Because it's not adding. –  Milo Mar 12 at 21:50

19 Answers 19

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)
share|improve this answer
    
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 at 18:51
2  
Umm this is a long solution, but it has 12 upvotes. What is going on with code-golf's voting? –  Quincunx Mar 13 at 5:16
    
@Quincunx Yes you are right its not popularity contest! –  Mukul Kumar Mar 13 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 Mar 13 at 6:56
    
@n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳, absolutly ! Thank you for pointing this out. Fixed now :) –  Michael Mar 13 at 12:54

J (9 characters)

A short answer in J:

^.(^.2)^~ 32
share|improve this answer
1  
...and I do not speak J. What does it say? –  CousinCocaine Mar 13 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)) –  ברוכאל Mar 13 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}

As per the comments:

  • / 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
$ 
share|improve this answer
    
I think I see a forward slash in there. –  Milo Mar 12 at 6:22
    
@Milo that / is part of a bash parameter expansion and not a division operator. Allowed or not? –  DigitalTrauma Mar 12 at 6:24
1  
I would allow it, it's not a mathematical operator in this case... –  WallyWest Mar 12 at 6:25
1  
-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 at 6:30
2  
@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: + - * / %" ;-) –  DigitalTrauma Mar 12 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(' ','')
share|improve this answer
1  
As already said, * and + are broken KEYS (whatever you use them for). –  ברוכאל Mar 12 at 9:58
2  
@ברוכאל: 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 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. –  ברוכאל Mar 12 at 10:01
    
Your answer is going to have problem with miniscule amount of money, e.g. 0.05. –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 13 at 11:37
    
You can use `input` (backticks included) instead of raw_input. –  nyuszika7h Jun 12 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
share|improve this answer
2  
Exponentiation is still a mathematical operation, and * is disallowed in any mathematical form as per the rules of the challenge. –  Tony H. Mar 12 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. –  ברוכאל Mar 12 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. –  ברוכאל Mar 12 at 10:03
1  
@ברוכאל 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 H. Mar 12 at 14:14
1  
Perhaps × and ÷ are allowed, those are not listed. –  marinus Mar 12 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.

share|improve this answer
    
Wait... what ? Please give more details of how it works for those (like me) who don't know R. –  Michael Mar 12 at 18:50
    
@Michael updated my answer to explain the code –  Rift Mar 12 at 20:27
    
Ok got it, thanks –  Michael Mar 12 at 21:47
    
Your solution doesn't do any rounding. –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 13 at 12:02
    
@n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ 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 at 13:11

dc + sed + pipes (44 characters)

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

dc -e 5o?p|sed -e 's/\(.\)$/.\1/'|dc -e 5i?p

It will ask for an INTEGER input and compute 20% with a tricky way. Input is converted to base 5 (easy to do with many other tools but wait...); a dot is appended before the last digit with sed (unfortunately, dc can't handle strings very well), and THEN, dc converts back from base 5 on a float number (not all tools can do that).

share|improve this answer
1  
"INTEGER input" doesn't meet the spec. I think you can fix it by changing your sed expression: dc -e 5o?p|sed 's/\(.\)\./.\1/'|dc -e 5i?p. With this and removing seds -es, this is 42. But the result is still not to spec (not 2 decimal places) –  DigitalTrauma Mar 12 at 15:42
    
@DigitalTrauma. You are right. But this solution was actually rather a proof of concept and I was more interested by the unusual property of base conversion in dc (and also in bc). Thank you for your comment and your fix in sed. –  ברוכאל Mar 12 at 15:46

Python, 88

This is no where near short, but this demonstrate how a normal mental division by five should be done. This assumes that the input must be of the form xx.xx

import math
a,b=raw_input().split('.')
print'%.2f'%math.ldexp(float(a[0]+'.'+a[1]+b),1)

Or for input of any length, an addition of 3 characters is required.

import math
a,b=raw_input().split('.')
print'%.2f'%math.ldexp(float(a[:-1]+'.'+a[-1]+b),1)

Explanation: We take the input as string, then move the decimal point one place forward (dividing by 10). We then cast it to a float, and use the ldexp function to multiply it by 2.

Note that in this answer, the + are string concatenation operators, and the % are used to format print.

If you insist on not using any of these characters, here is a 159 character solution:

import math
a,b=raw_input().split('.')
l=[a[0]]
l.append('.')
l.append(a[1])
l.append(b)
c=str(math.ldexp(float(''.join(l)),1))
print ''.join([c[0:2],c[2:4]])
share|improve this answer
    
Already said for many other answers, but I really don't think that + and - are allowed since the KEYS are broken (whatever they mean in your piece of code). –  ברוכאל Mar 12 at 9:59
    
@ברוכאל: See my response to your comment in my answer –  Abhijit Mar 12 at 10:01
    
Used your .split('.') in my answer, chopped one char –  user80551 Mar 12 at 10:34

dc + sed -- 45 * 0.8 = 36

(Inspired by the answer by ברוכאל)

  • Handles any tip amount (integer or float)

Example runs (input is accepted via STDIN):

$ dc -e 5o?.0+p|sed 's/\(.\)\./.\1/'|dc -e 5i?p
42
8.400
$ dc -e 5o?.0+p|sed 's/\(.\)\./.\1/'|dc -e 5i?p
20.96
4.1920
share|improve this answer
    
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. –  ברוכאל Mar 12 at 17:42
    
@ברוכאל I didn't realize that the + even in this context might qualify as addition. –  devnull Mar 12 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 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.

share|improve this answer
3  
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? –  ברוכאל Mar 12 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
share|improve this answer
    
Please, see my comments to your other solution (in Mathematica); this code can really be simplified much. –  ברוכאל Mar 12 at 8:24
    
Input x,y ??? Works in 83/84. –  Timtech Mar 12 at 11:09
    
@Timtech Doesn't work in 89, but maybe I can do something like Input{x,y} (does 83/84 have ln?) –  Quincunx Mar 12 at 18:51
    
@Quincunx Yes, see my new answer. –  Timtech Mar 12 at 20:20

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 :(

share|improve this answer

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

share|improve this answer
    
I think you can do [-3:] instead of [-3:-1] –  Quincunx Mar 12 at 18:53
    
@Quincunx Can't , the -1 is to truncate to two decimals. –  user80551 Mar 13 at 3:42
    
@n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Yep, fixed it. –  user80551 Mar 13 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...

share|improve this answer
    
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 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',"$`.$&"
share|improve this answer
    
@n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳: Thanks, fixed now. –  Heiko Oberdiek Mar 13 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))

Readable version:

function tip(m) {
    var s = 'x'.repeat(m.replace('.', '')) + 'xxxx';
    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.

share|improve this answer

TI Basic, 10 - 20% = 8 and 6

Input A,B
.01AB

Other version, 6 :

Input A
.2A

Note: the Input operator is a 2 byte symbol

Explanation at request:

The Input operator asks the user for a variable or variables, then the last line multiplies the .01, the A, and the B and outputs it.

share|improve this answer
    
Nice, but could you give some more explanation, since I don't know the TI Basic language and can't recognize anything known here ;-) –  ברוכאל Mar 12 at 14:48
3  
-1. This is not allowed. .2AB is exactly .2*A*B which is explicitly not allowed. "No use of the following in mathematical form operators: + - * / % " means that the equivalents cannot be used as well. –  Quincunx Mar 12 at 15:59
1  
Agree with @Quincunx ! Surely it's not visible, but you still call the multiplication operator. –  Michael Mar 12 at 16:07

Haskell 32 Chars -20% = 25.6 Chars

t y x=log $(^x)$(**0.01)$ exp y

Abuses the fact that exponents become multiplication in logarithms.

share|improve this answer

C: 66

main(){float f;scanf("%f",&f);printf("%.2f",log(pow(exp(.2),f)));}

Uses the f * 0.2 == ln((e^.2)^f) trick

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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