Calculer un pourboire

16

Vous et un ami entrez dans un bar. Le barman vous traite bien, vous décidez donc de lui donner un pourboire. Donc, vous sortez votre fidèle ordinateur de poche et écrivez un programme rapide pour calculer un pourboire car il n'a pas de calculatrice intégrée. Mais attendez! Vos clés d'opérateur sont cassées! Votre tâche consiste à calculer un pourboire de 20% pour tout montant d'entrée donné. Les entrées de test seront sous la forme de xx.xx, par exemple 20,96. Voici les règles:

  • Aucune utilisation des opérateurs de forme mathématique suivants: + - * / %(Merci Wally West)
  • Aucune utilisation des fonctions de pourcentage ou des API intégrées
  • Pas d'accès au réseau
  • Pas d'utilisation evalou similaire
  • Pas de calculatrice Windows (oui, les gens y ont déjà répondu)
  • Pas de fonctions de pointe intégrées (pas que n'importe quelle langue en aurait une)

La sortie doit être arrondie à deux décimales près.

Le score est basé sur la longueur en octets.

-20% si votre programme peut accepter n'importe quel montant de pourboire. L'entrée pour le montant sera donnée sous la forme de xx par exemple 35 pas 0,35

Milo
la source
5
@mniip: Un pourboire est une somme d'argent bizarre que vous êtes censé payer dans un restaurant qui ne fait pas partie du prix officiel. Je ne sais pas s'ils font ça en Russie.
user2357112 prend en charge Monica
5
Oh, cette nouvelle génération ... Je préfère utiliser du papier et un stylo si je ne peux pas diviser mentalement un nombre par 5.
VisioN
4
@VisioN Remarque: diviser par cinq équivaut à diviser par 10 puis à multiplier par 2, et les deux devraient être des opérations mentales très faciles.
user12205
1
Quelqu'un peut-il clarifier les règles: l'utilisation des opérations interdites est-elle autorisée si vous n'utilisez pas ces opérateurs? La multiplication est-elle autorisée si vous n'utilisez pas *?
Ypnypn
2
@TheDoctor est-ce vraiment un doublon? Parce que ça n'ajoute rien.
Milo

Réponses:

18

Javascript 81

EDIT : Le résultat est maintenant un véritable arrondi, non tronqué.

N'utilisez AUCUN math ici, juste une manipulation de chaîne et des opérateurs au niveau du bit.
Tous les +caractères sont une concaténation de chaînes ou une conversion de chaîne en flottant .
Fonctionne pour toutes les entrées et sorties xx.xx au format (x) x.xx

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

Astuce expliquée: 20% est divisé par 10 et multiplié par 2.

  • Faites une division par 10 en déplaçant le point vers la gauche (manipulation de chaîne)
  • Multipliez chaque partie par 2 en déplaçant les bits vers la gauche (opération au niveau du bit)
Michael M.
la source
Lorsque l'entrée est 99.99, cela revient 19.998, donc ce n'est pas "arrondi à deux décimales" selon l'OP.
Geobits
2
Umm c'est une longue solution, mais elle a 12 votes positifs. Que se passe-t-il avec le vote par code-golf?
Justin
@Quincunx Oui, vous avez raison, ce n'est pas un concours de popularité!
Mukul Kumar
Puisqu'il s'agit d'un golf de code, je ne gagnerai probablement pas, mais cela ne signifie pas que les gens ne peuvent pas aimer ma solution ... Souvent, les gagnants de golf de code ne sont pas ceux qui ont le plus de votes positifs.
Michael M.
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳, absolument! Merci de l'avoir signalé. Corrigé maintenant :)
Michael M.
6

J (9 caractères)

Une réponse courte en J:

^.(^.2)^~ 32
Thomas Baruchel
la source
1
... et je ne parle pas J. Que dit-il?
CousinCocaine
Il dit: calculer 32 levés pour alimenter le journal (2); généralement, l'exposant est à la droite de ^mais ~indique ici que l'ordre doit être inversé; (^.2)est log (.2), ​​et l'initiale ^.qui est exécutée en dernier est le logarithme de tout le calcul précédent: donc log (32 ^ log (.2))
Thomas Baruchel
4

Pure bash, 50 43 caractères

Je suis sûr que ce sera battu, mais voici un début:

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

Selon les commentaires:

  • /n'est pas un opérateur de division ici, il fait partie d'une expansion des paramètres de substitution de motifs
  • % n'est pas un opérateur modulo ici, il fait partie d'une expansion de paramètres
  • - n'est pas un opérateur de soustraction ici, c'est une négation, qui a été autorisée selon les commentaires

Production:

$ ./20pct.sh 0,96
.19
$ ./20pct.sh 20,96
4.19
$ ./20pct.sh 1020.96
204.19
$ 
Traumatisme numérique
la source
Je pense que je vois une barre oblique là-dedans.
Milo
@Milo qui /fait partie d'une expansion de paramètre bash et non un opérateur de division. Autorisé ou non?
Digital Trauma
1
Je le permettrais, ce n'est pas un opérateur mathématique dans ce cas ...
WallyWest
1
-3 agit comme une négation et non une soustraction ... @Milo, vous devez tenir compte de la négation et des autres façons dont ces opérateurs peuvent être utilisés en dehors de leurs équivalents mathématiques ... par exemple + peut être utilisé comme concaténateur en JavaScript. .. Puis-je faire une suggestion? Remplacez "Aucune utilisation des opérateurs suivants: + - * /%" par "Aucune utilisation des opérateurs suivants dans leur forme mathématique: + - * /%"
WallyWest
2
@WallyWest Pour jouer l'avocat du diable, la négation ici est toujours un opérateur mathématique. Peut-être "Pas d'utilisation des opérateurs suivants dans leur forme mathématique non unaire: + - * /%" ;-)
Digital Trauma
4

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 (sans bonus)

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

Remarque

  • + est utilisé pour la concaténation de chaînes
  • * utilisé pour créer des copies de chaîne

Non golfé

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:])

Remarque

Dans l'esprit de la question, je crois que la solution suivante, bien qu'elle respecte toutes les règles de la question, est un abus

Python 41

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

finalement

Si vous insistez pour que les symboles mathématiques soient interdits, c'est une solution à 90 caractères

Python 90 (sans symbole mathématique)

print' '.join(str(int(raw_input().replace(".",""))<<1)).replace(' ','.',1).replace(' ','')
Abhijit
la source
1
Comme nous l' avons dit, *et +sont brisés KEYS (tout ce que vous les utilisez pour).
Thomas Baruchel
2
@ ברוכאל: No use of the following in mathematical form operators: + - * / % (Thanks Wally West). En d'autres termes, la question doit être reformulée. Et je ne les ai pas utilisés sous forme mathématique
Abhijit
D'accord, mais dans ce cas, le downvote de la solution APL n'était pas vraiment juste, car aucune autre solution n'a été downvote pour cette raison.
Thomas Baruchel
Votre réponse va avoir un problème avec une somme d'argent minuscule, par exemple 0.05.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
Vous pouvez utiliser `input`(backticks inclus) au lieu de raw_input.
nyuszika7h
4

APL (9 caractères, nouveau code à 7 caractères, fixé à 13 caractères)

Calculez 20% du montant donné.

{⍟⍵*⍨*.2} 32

Dans APL *est l'opérateur exponentiel.

Essayez-le en ligne .

Mais pourquoi utiliser une fonction pour ça? Voir cette nouvelle version:

⍟(*.2)* 32

Essayez-le en ligne .

S'il vous plaît, avant de voter, le *n'est pas interdit en tant que CLÉ et cela ne signifie pas la multiplication ici.

OK, voici la version arrondie à 2 décimales (Dyalog APL):

⎕PP←2⋄⍟(*.2)* 32.01
Thomas Baruchel
la source
2
L'exponentiation est toujours une opération mathématique, et *est interdite sous toute forme mathématique selon les règles du défi.
Tony Ellis
L'exponentiation n'est pas interdite ici et d'autres solutions l'utilisent réellement, mais vous avez raison concernant le fait qu'il *est interdit comme clé et non comme sa signification mathématique.
Thomas Baruchel
@Tony H. S'il vous plaît, pourriez-vous supprimer votre downvote, car évidemment tous les commentaires dans d'autres solutions semblent finalement accepter ces CLÉS tant qu'elles ne sont pas utilisées pour les opérations mathématiques interdites dans la liste initiale.
Thomas Baruchel
1
@ ברוכאל Je crois comprendre que l'utilisation d'un astérisque d'une manière qui se rapporte à une signification mathématique est interdite, y compris l'exponentiation. Jusqu'à présent, toutes les autres réponses utilisant des exposants sont dans une langue utilisant le signe d'insertion (^ ) pour un tel opérateur, ou un appel de fonction est utilisé. Il n'y a aucune spécification par l'OP qui *n'est interdite que si elle est utilisée dans le contexte de la multiplication. Je soupçonne qu'il serait utile que OP se prononce sur cette question, pour déterminer lequel d'entre nous interprète mal les règles du défi et pour dissiper la confusion.
Tony Ellis
1
Peut ×- être et ÷sont autorisés, ceux-ci ne sont pas répertoriés.
marinus
4

R, 30 27 36 34

Mis à jour pour arrondir à 2 décimales

Sauvé 2 personnages grâce à plannapus

Crée un vecteur de 0 à x et prend le 2ème élément.

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

Exemple:

> a(20.36)
[1] 4.07

Plus d'explications:

seq(0,x,len=6)

crée un vecteur de longueur 6 de 0 à la valeur d'entrée x, les valeurs intermédiaires étant également espacées.

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

La première valeur est alors 0%, la seconde 20%, la troisième 40%, etc.

Crevasse
la source
Attends quoi ? Veuillez donner plus de détails sur la façon dont cela fonctionne pour ceux (comme moi) qui ne connaissent pas R.
Michael M.
@Michael a mis à jour ma réponse pour expliquer le code
Rift
Votre solution ne fait aucun arrondi.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ vous avez raison (mais la plupart des solutions n'arrondissent rien). 9 caractères supplémentaires feraient un arrondi "normal". Seul arrondir serait beaucoup plus difficile ...
Rift
@Rift: J'ai testé plusieurs réponses (principalement Python, JS et Perl, car elles sont facilement disponibles) et la plupart d'entre elles font des arrondis. Cependant, aucun de ceux que j'ai testés n'est complet.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
3

dc + sed + pipes (44 caractères)

Ma troisième réponse (un APL, un J, et maintenant un avec l'ancien et vénérable dc).

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

Il demandera une entrée INTEGER et calculera 20% d'une manière délicate. L'entrée est convertie en base 5 (facile à faire avec de nombreux autres outils mais attendez ...); un point est ajouté avant le dernier chiffre avec sed (malheureusement, dc ne peut pas très bien gérer les chaînes), et ALORS, dc se reconvertit à partir de la base 5 sur un nombre flottant (tous les outils ne peuvent pas le faire).

Thomas Baruchel
la source
1
"Entrée INTEGER" ne correspond pas à la spécification. Je pense que vous pouvez le réparer en changeant votre expression sed: dc -e 5o?p|sed 's/\(.\)\./.\1/'|dc -e 5i?p. Avec cela et en supprimant seds -es, c'est 42. Mais le résultat n'est toujours pas conforme (pas 2 décimales)
Digital Trauma
@DigitalTrauma. Tu as raison. Mais cette solution était en fait plutôt une preuve de concept et j'étais plus intéressé par la propriété inhabituelle de la conversion de base en dc (et aussi en bc). Merci pour ton commentaire et ta correction en sed.
Thomas Baruchel
2

Python, 88

Ce n'est pas loin d'être court, mais cela montre comment une division mentale normale par cinq devrait être effectuée. Cela suppose que l'entrée doit être de la forme xx.xx

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

Ou pour une entrée de n'importe quelle longueur, un ajout de 3 caractères est requis.

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

Explication: Nous prenons l'entrée sous forme de chaîne, puis déplaçons la virgule décimale d'une place vers l'avant (en divisant par 10). Nous le jetons ensuite sur un flotteur et utilisons leldexp fonction pour le multiplier par 2.

Notez que dans cette réponse, les +opérateurs de concaténation sont des chaînes et %sont utilisés pour formaterprint .

Si vous insistez pour ne pas utiliser l'un de ces caractères, voici une solution à 159 caractères:

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]])
user12205
la source
Déjà dit pour de nombreuses autres réponses, mais je ne pense vraiment pas +et -sont autorisées car les clés sont cassées (quoi qu'elles signifient dans votre morceau de code).
Thomas Baruchel
@ ברוכאל: Voir ma réponse à votre commentaire dans ma réponse
Abhijit
Utilisé votre .split('.')dans ma réponse, haché un caractère
user80551
2

dc + sed - 45 * 0,8 = 36

(Inspiré par la réponse de ברוכאל )

  • Gère n'importe quel montant de pourboire (entier ou flottant)

Exemple s'exécute (l'entrée est acceptée 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
devnull
la source
L' .0+idée est géniale; J'ai voté pour votre solution inspirée de la mienne, mais certains diront que vous utilisez l'addition; peut-être une solution? J'ai essayé dc -e 9k5o?v2^pmais c'est 2 caractères de plus.
Thomas Baruchel
@ ברוכאל Je ne savais pas que le +, même dans ce contexte, pouvait être considéré comme un ajout.
devnull
@ ברוכאל Je vais supprimer celui-ci. Vous demander de modifier votre afin qu'il puisse gérer les flotteurs et se qualifier pour -20%!
devnull
2

Mathematica, 19

Log[(E^.2)^Input[]]

Aucune utilisation des opérateurs mathématiques +, -, *,/ ou %. Utilise les propriétés des logarithmes pour calculer la réponse; lorsque vous simplifiez l'expression, vous obtenez.2*Input[]

Avec le bonus ( 30 * 0,8 = 24 ):

Log[((E^.01)^Input[])^Input[]]

Saisissez d'abord le pourcentage, puis le montant.

Lorsque vous simplifiez l'expression, vous obtenez Input[]*Input[]*.01 .

Merci à ברוכאל pour son aide à raccourcir le code.

Justin
la source
3
Êtes-vous vraiment sûr que cela ne peut pas être simplifié? Pour moi Log[E^2]ou Log[E^Input[]]peut être écrit plus rapidement. Même 10^-1peut être écrit .01(bien que je n'utilise pas Mathematica mais je suis sûr que c'est possible). L'expression entière (E^10^-1)^Log[E^2]semble être quelque chose comme ça E^.2, n'est-ce pas?
Thomas Baruchel
1

TI-89 Basic - 39 * 0,8 = 31,2

Input y:Input x:Disp ln(((e^y)^.01)^x))

Fonctionne en saisissant les deux nombres, puis en utilisant les propriétés du logarithme pour calculer x * y / 100.

Si je peux supposer l'entrée du placement dans des variables globales xet y, alors c'est beaucoup plus court, pour un score de 17 * 0,8 = 13,6 :

ln(((e^y)^.01)^x)

Sans bonus ( 12 ):

ln((e^.2)^x)

Mais si elle doit être enveloppée dans une fonction, alors cela fonctionne ( 38 caractères, pour 30.4 ):

:f(x,y):Func:ln(((e^y)^.01)^x):EndFunc
Justin
la source
Veuillez voir mes commentaires sur votre autre solution (dans Mathematica); ce code peut vraiment être beaucoup simplifié.
Thomas Baruchel
Input x,y??? Fonctionne en 83/84.
Timtech
@Timtech Ne fonctionne pas en 89, mais peut-être que je peux faire quelque chose comme Input{x,y}(83/84 en a ln?)
Justin
@Quincunx Oui, voir ma nouvelle réponse.
Timtech
žr¹msmžr.n- port sans vergogne de ce code dans 05AB1E.
Magic Octopus Urn
1

PHP 107 * .8 = 85,6

ne peut pas vraiment fonctionner pour le code-golf avec PHP, mais au moins je peux opérer sur des chaînes. accepte les deux nombres comme arguments de ligne de commande.

<? @$r=strrev;unset($argv[0]);echo$r(substr_replace($r(str_replace('.','',array_product($argv)))),'.',2,0);

a dû l'inverser deux fois car je ne peux pas utiliser -2 :(

Einacio
la source
1

Python, 81 80 89 caractères

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

Explication

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]

Techniquement, cela triche car il tronque à deux décimales plutôt que de l'arrondir, mais je peux affirmer qu'il arrondit (mieux pour vous, moins de pourboire).

user80551
la source
Je pense que vous pouvez faire à la [-3:]place de[-3:-1]
Justin
@Quincunx Impossible, le -1 est de tronquer à deux décimales.
user80551
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Oui, corrigé.
user80551
1

JavaScript 251 (restriction forcée: pas de +, -, *,? Ou% de quelque manière que ce soit)

Bien que je sache que cela ne gagnera pas, je me suis dit que j'essaierais d'obtenir des points de brownie en adoptant une approche très stricte et sans même penser à utiliser les opérateurs restreints sous quelque forme que ce soit ... en conséquence, j'ai trouvé cette beauté ...

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

J'ai utilisé des opérations au niveau du bit pour créer la fonction Ajouter A, puis j'ai commencé à chaîner à partir de là:

La fonction de division entière a Dutilisé une série d'addition négative (soustraction sous forme de A(x,A(~y,1)sur une boucle; le reste est une manipulation de chaîne et une concaténation afin d'éviter d'utiliser des +opérateurs de concaténation ...

Le numéro doit être fourni sous forme décimale avec deux décimales pour que cela fonctionne ...

WallyWest
la source
Ah, ça le sera maintenant ... même si si je devais respecter les nouvelles règles, je devais l'étendre ... 251 octets maintenant ...
WallyWest
1

Perl, 50 60 octets

$_=<>;s|\.||;$_<<=1;$_="00$_";m|\d{3}$|;printf'%.2f',"$`.$&"

L'entrée est attendue à STDIN. Il doit contenir le séparateur décimal avec deux chiffres décimaux. La sortie est écrite dans STDOUT.

Mise à jour: l'étape $_<<=1supprime les zéros non significatifs. Par conséquent m|\d{3}$|, ne correspondrait pas aux factures <1. Par conséquent, dix octets $_="00$ont été ajoutés, maintenant même0.00 fonctionne .

Exemples:

  • Entrée:, 20.96sortie:4.19
  • Entrée:, 12.34sortie:2.47

Version non golfée:

$_=<>;
s|\.||; # multiply by 100
$_ <<= 1; # multiply by 2
$_="00$_";
m|\d{3}$|; # divide by 1000
printf '%.2f'," $`.$&"

Tout d'abord, le nombre est lu à partir de STDIN. Ensuite, le point décimal est supprimé, multiplié par 100. Ensuite, le montant est doublé par un opérateur de décalage. Ensuite, le point décimal est réinséré et le résultat est imprimé et arrondi à deux chiffres décimaux.

50 octets, si facture ≥ 1:

Si x.xxest supérieur ou égal à 1.00, 10 octets peuvent être supprimés:

$_=<>;s|\.||;$_<<=1;m|\d{3}$|;printf'%.2f',"$`.$&"
Heiko Oberdiek
la source
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳: Merci, corrigé maintenant.
Heiko Oberdiek
1

JavaScript (ES6) (Regex) 142

Regex est génial et il peut faire beaucoup de choses. Il peut même faire des 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))

Version lisible:

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

La tip()fonction attend l'argument String, plutôt que Number.

Toutes les instances de *, /, +ne sont pas liés à des opérations mathématiques.

  • + est la concaténation de chaînes dans tous les cas où elle est utilisée.
  • * fait partie de la syntaxe RegExp
  • / est le délimiteur du littéral RegExp

L'entrée doit utiliser .comme point décimal, et il doit y avoir avoir 2 chiffres après le point décimal.

Extrait de pile

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

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
la source
0

Haskell 32 caractères -20% = 25,6 caractères

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

Abuse le fait que les exposants deviennent multiplication dans les logarithmes.

PyRulez
la source