Calcule una propina

16

Usted y un amigo entran a un bar. El camarero te trata bien, así que decides darle propina. Entonces saca su confiable computadora de bolsillo y escribe un programa rápido para calcular una propina para usted, ya que no tiene una calculadora incorporada. ¡Pero espera! ¡Sus llaves de operador están rotas! Su tarea es calcular una propina del 20% para cualquier cantidad de entrada dada. Las entradas de prueba tendrán la forma de xx.xx, por ejemplo, 20.96. Estas son las reglas:

  • No se utiliza lo siguiente en operadores de forma matemática: + - * / %(Gracias Wally West)
  • Sin uso de funciones porcentuales o API incorporadas
  • No acceder a la red
  • No uso de evalo similar
  • Sin calculadora de Windows (sí, la gente ha respondido con ella antes)
  • Sin funciones de tip incorporadas (no es que cualquier idioma tenga una)

La salida debe redondearse a dos decimales.

La puntuación se basa en la longitud en bytes.

-20% si su programa puede aceptar cualquier cantidad de propina. La entrada para la cantidad se dará en forma de xx, por ejemplo 35 no 0.35

Milo
fuente
55
@mniip: Una propina es una cantidad extra de dinero extra que se espera que pagues en un restaurante que no es parte del precio oficial. No sé si hacen eso en Rusia.
user2357112 es compatible con Monica
55
Oh, esa nueva generación ... Preferiría usar papel y bolígrafo si no puedo dividir mentalmente un número entre 5.
VisioN
44
@VisioN Nota: dividir entre cinco es equivalente a dividir entre 10 y luego multiplicar por 2, y ambos deberían ser operaciones mentales muy fáciles.
user12205
1
¿Alguien puede aclarar las reglas: está permitido usar las operaciones prohibidas si no usa esos operadores? ¿Se permite la multiplicación si no la usas *?
Ypnypn
2
@TheDoctor, ¿es realmente un duplicado? Porque no está agregando.
Milo

Respuestas:

18

Javascript 81

EDITAR : El resultado ahora es un redondeo real, no truncado.

No use NINGUNA matemática aquí, solo manipulación de cadenas y operadores bit a bit.
Todos los caracteres +son concatenación de cadenas o conversión de cadena a flotante .
Funciona para cualquier entrada y salida xx.xx en formato (x) x.xx

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

Truco explicado: el 20% se divide por 10 y se multiplica por 2.

  • Haz una división por 10 moviéndote el punto a la izquierda (manipulación de cuerdas)
  • Multiplique cada parte por 2 moviendo bits hacia la izquierda (operación bit a bit)
Michael M.
fuente
Cuando la entrada es 99.99, esto regresa 19.998, por lo que no se "redondea a dos decimales" según el OP.
Geobits
2
Umm, esta es una solución larga, pero tiene 12 votos a favor. ¿Qué está pasando con la votación de code-golf?
Justin
@Quincunx Sí, tienes razón, ¡no es un concurso de popularidad!
Mukul Kumar
Dado que es un código de golf, probablemente no gane, pero esto no significa que a la gente no le guste mi solución ... A menudo, los ganadores de código de golf no son los que tienen más votos a favor.
Michael M.
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳, ¡absolutamente! Gracias por señalar esto. Reparado ahora :)
Michael M.
6

J (9 caracteres)

Una respuesta corta en J:

^.(^.2)^~ 32
Thomas Baruchel
fuente
1
... y no hablo J. ¿Qué dice?
CousinCocaine
Dice: calcular 32 elevado al registro de energía (2); generalmente, el exponente está a la derecha de, ^pero aquí ~indica que el orden debe invertirse; (^.2)es log (.2), ​​y la inicial ^.que se ejecuta en último lugar es el logaritmo de todo el cálculo anterior: por lo tanto log (32 ^ log (.2))
Thomas Baruchel
4

Pure bash, 50 43 caracteres

Estoy bastante seguro de que esto será mejor, pero aquí hay un comienzo:

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

Según los comentarios:

  • /no es un operador de división aquí, es parte de una expansión del parámetro de sustitución de patrón
  • % no es un operador de módulo aquí, es parte de una expansión de parámetros
  • - no es un operador de resta aquí, es una negación, que se permitió según los comentarios

Salida:

$ ./20pct.sh 0.96
.19
$ ./20pct.sh 20.96
4.19
$ ./20pct.sh 1020.96
204,19
PS 
Trauma digital
fuente
Creo que veo un corte hacia adelante allí.
Milo
@Milo que /es parte de una expansión de parámetros bash y no un operador de división. ¿Permitido o no?
Digital Trauma
1
Lo permitiría, no es un operador matemático en este caso ...
WallyWest
1
-3 actúa como una negación, no como una resta ... @Milo, debe tener en cuenta la negación y otras formas en que estos operadores se pueden usar aparte de sus equivalentes matemáticos ... por ejemplo, + se puede usar como un concatenador en JavaScript. .. ¿Puedo hacer una sugerencia? Cambie "Sin uso de los siguientes operadores: + - * /%" a "Sin uso de los siguientes operadores en su forma matemática: + - * /%"
WallyWest
2
@WallyWest Para jugar al abogado del diablo, la negación aquí sigue siendo un operador matemático. Quizás "No utilizar los siguientes operadores en su forma matemática no unaria: + - * /%" ;-)
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 (sin bonificación)

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

Nota

  • + se usa para la concatenación de cadenas
  • * usado para crear copias de cadena

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

Nota

En el espíritu de la pregunta, creo que la siguiente solución, aunque sigue todas las reglas de la pregunta, es un abuso

Python 41

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

Finalmente

Si insiste en que los símbolos matemáticos están prohibidos, ella es una solución de 90 caracteres

Python 90 (sin ningún símbolo matemático)

print' '.join(str(int(raw_input().replace(".",""))<<1)).replace(' ','.',1).replace(' ','')
Abhijit
fuente
1
Como ya se dijo, *y +están CLAVES rotas (para lo que sea que las use).
Thomas Baruchel
2
@ ברוכאל: No use of the following in mathematical form operators: + - * / % (Thanks Wally West). En otras palabras, la pregunta necesita ser reformulada. Y no los he usado en forma matemática
Abhijit
De acuerdo, pero en ese caso, el voto negativo de la solución APL no fue realmente justo, ya que ninguna otra solución ha sido rechazada por ese motivo.
Thomas Baruchel
Su respuesta tendrá un problema con una cantidad minúscula de dinero, por ejemplo 0.05.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
Puede usar `input`(backticks incluidos) en lugar de raw_input.
nyuszika7h
4

APL (9 caracteres, nuevo código con 7 caracteres, corregido con 13 caracteres)

Calcule el 20% de la cantidad dada.

{⍟⍵*⍨*.2} 32

En APL *es el operador exponencial.

Pruébalo en línea .

Pero, ¿por qué usar una función para eso? Ver esta nueva versión:

⍟(*.2)* 32

Pruébalo en línea .

Por favor, antes de votar, *no está prohibido como CLAVE y no significa multiplicación aquí.

OK, aquí está la versión redondeando a 2 decimales (Dyalog APL):

⎕PP←2⋄⍟(*.2)* 32.01
Thomas Baruchel
fuente
2
La exponenciación sigue siendo una operación matemática y *no está permitida en ninguna forma matemática según las reglas del desafío.
Tony Ellis
La exponenciación no está prohibida aquí y otras soluciones realmente la usan, pero tiene razón con respecto al hecho de que *está prohibido como una clave y no como su significado matemático.
Thomas Baruchel
@ Tony H. Por favor, ¿podría eliminar su voto negativo, ya que obviamente todos los comentarios en otras soluciones finalmente aceptan tales CLAVES, siempre y cuando no se usen para las operaciones matemáticas prohibidas en la lista inicial.
Thomas Baruchel
1
@ ברוכאל Tengo entendido que el uso de un asterisco de cualquier manera que pertenezca a un significado matemático está prohibido, eso incluye la exponenciación. Hasta ahora, cualquier otra respuesta que use exponentes está en un lenguaje que usa el intercalador ( ^) para dicho operador, o se usa una llamada de función. El OP no especifica ninguna especificación que *no se permita solo si se usa en el contexto de la multiplicación. Sospecho que sería útil si OP decidiera sobre esto, para determinar cuál de nosotros está malinterpretando las reglas del desafío y aclarar la confusión.
Tony Ellis
1
Quizás ×y ÷están permitidos, esos no están listados.
marinus
4

R, 30 27 36 34

Actualizado a redondear a 2 decimales

Salvado 2 personajes gracias a plannapus

Crea un vector de 0 a xy toma el segundo elemento.

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

Ejemplo:

> a(20.36)
[1] 4.07

Explicación adicional:

seq(0,x,len=6)

crea un vector de longitud 6 desde 0 hasta el valor de entrada x, con los valores intermedios igualmente espaciados.

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

El primer valor es entonces 0%, el segundo 20%, tercero 40%, etc.

Grieta
fuente
Esperar lo ? Por favor, brinde más detalles de cómo funciona para aquellos (como yo) que no conocen R.
Michael M.
@Michael actualizó mi respuesta para explicar el código
Rift
Su solución no hace ningún redondeo.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ tienes razón (pero la mayoría de las soluciones no están redondeando nada). 9 caracteres adicionales harían redondeos "normales". Solo redondear sería mucho más difícil ...
Rift
@Rift: He probado varias respuestas (principalmente Python, JS y Perl, ya que están fácilmente disponibles) y la mayoría de ellas hacen redondeo. Sin embargo, ninguno de los que he probado se acumula.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
3

dc + sed + tuberías (44 caracteres)

Mi tercera respuesta (una APL, una J, y ahora una con el viejo y venerable DC).

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

Solicitará una entrada INTEGER y calculará el 20% de una manera complicada. La entrada se convierte a la base 5 (fácil de hacer con muchas otras herramientas pero espere ...); se agrega un punto antes del último dígito con sed (desafortunadamente, dc no puede manejar cadenas muy bien), y ENTONCES, dc convierte de nuevo desde la base 5 en un número flotante (no todas las herramientas pueden hacer eso).

Thomas Baruchel
fuente
1
La "entrada INTEGER" no cumple con las especificaciones. Creo que se puede solucionar cambiando la expresión de sed: dc -e 5o?p|sed 's/\(.\)\./.\1/'|dc -e 5i?p. Con esto y eliminando seds -es, esto es 42. Pero el resultado aún no es específico (no 2 decimales)
Digital Trauma
@DigitalTrauma. Tienes razón. Pero esta solución era en realidad una prueba de concepto y me interesaba más la inusual propiedad de la conversión de bases en CC (y también en CC). Gracias por tu comentario y tu solución en sed.
Thomas Baruchel
2

Python, 88

Esto no es para nada corto, pero esto demuestra cómo debe hacerse una división mental normal por cinco. Esto supone que la entrada debe tener la forma xx.xx

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

O para la entrada de cualquier longitud, se requiere una adición de 3 caracteres.

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

Explicación: Tomamos la entrada como una cadena, luego movemos el punto decimal un lugar hacia adelante (dividiendo por 10). Luego lo lanzamos a un flotador y usamos la ldexpfunción para multiplicarlo por 2.

Tenga en cuenta que en esta respuesta, +son operadores de concatenación de cadenas y %se utilizan para formatear print.

Si insiste en no usar ninguno de estos caracteres, aquí hay una solución de 159 caracteres:

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]])
usuario12205
fuente
Ya lo dije para muchas otras respuestas, pero realmente no lo creo +y estoy -permitido ya que las CLAVES están rotas (lo que sea que signifiquen en su código).
Thomas Baruchel
@ ברוכאל: Vea mi respuesta a su comentario en mi respuesta
Abhijit
Usé tu .split('.')en mi respuesta,
corté
2

dc + sed - 45 * 0.8 = 36

(Inspirado por la respuesta de ברוכאל )

  • Maneja cualquier cantidad de propina (entero o flotante)

Ejecuciones de ejemplo (la entrada se acepta a través de 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
fuente
La .0+idea es genial; He votado a favor de su solución inspirada en la mía, pero algunos pueden decir que está usando la adición; tal vez alguna solución? Lo intenté dc -e 9k5o?v2^ppero son 2 caracteres más.
Thomas Baruchel
@ ברוכאל No me di cuenta de que el + incluso en este contexto podría calificar como suma.
devnull
@ ברוכאל Eliminaré este. ¡Solicite que modifique su para que pueda manejar flotadores y calificar -20%!
devnull
2

Mathematica, 19

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

Sin el uso de los operadores matemáticos de +, -, *, /, o %. Utiliza propiedades de logaritmos para calcular la respuesta; cuando simplificas la expresión, obtienes.2*Input[]

Con la bonificación ( 30 * 0.8 = 24 ):

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

Ingrese el porcentaje primero, luego la cantidad.

Cuando simplificas la expresión, obtienes Input[]*Input[]*.01.

Gracias a ברוכאל por ayudarme a acortar el código.

Justin
fuente
3
¿Estás realmente seguro de que no se puede simplificar? Para mí Log[E^2]o Log[E^Input[]]se puede escribir más brevemente. Incluso 10^-1se puede escribir .01(aunque no uso Mathematica pero estoy bastante seguro de que sí). Toda la expresión (E^10^-1)^Log[E^2]parece ser algo así E^.2, ¿no?
Thomas Baruchel
1

TI-89 Basic - 39 * 0.8 = 31.2

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

Funciona ingresando los dos números y luego usando las propiedades del logaritmo para calcular x * y / 100.

Si puedo asumir la entrada de la ubicación en variables globales xy y, entonces, esto es mucho más corto, para un puntaje de 17 * 0.8 = 13.6 :

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

Sin bonificación ( 12 ):

ln((e^.2)^x)

Pero si necesita ser envuelto en una función, entonces esto funciona ( 38 caracteres, para 30.4 ):

:f(x,y):Func:ln(((e^y)^.01)^x):EndFunc
Justin
fuente
Por favor, vea mis comentarios a su otra solución (en Mathematica); Este código realmente se puede simplificar mucho.
Thomas Baruchel
Input x,y??? Funciona en 83/84.
Timtech
@Timtech no funciona en 89, pero tal vez pueda hacer algo como Input{x,y}(¿tiene 83/84 ln?)
Justin
@Quincunx Sí, mira mi nueva respuesta.
Timtech
žr¹msmžr.n- puerto descarado de este código en 05AB1E.
Urna mágica de pulpo
1

PHP 107 * .8 = 85.6

Realmente no puedo correr para code-golf con PHP, pero al menos puedo operar en cadenas. acepta ambos números como argumentos de línea de comandos.

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

tuve que revertirlo dos veces ya que no puedo usar -2 :(

Einacio
fuente
1

Python, 81 80 89 caracteres

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

Explicación

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]

Técnicamente, esto es trampa, ya que se trunca a dos decimales en lugar de redondearlo, pero puedo argumentar que se redondea (mejor para ti, menos propina).

usuario80551
fuente
Creo que puedes hacer en [-3:]lugar de[-3:-1]
Justin
@Quincunx no puede, el -1 es truncar a dos decimales.
user80551
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Sí, lo arregló.
user80551
1

JavaScript 251 (restricción forzada: no +, -, *,? O% de ninguna manera)

Si bien sé que esto no ganará, pensé que trataría de obtener puntos de brownie adoptando un enfoque muy estricto y ni siquiera pensar en usar los operadores restringidos en cualquier forma ... como resultado, se me ocurrió esta belleza...

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

Usé operaciones bit a bit para crear la función Agregar A, y luego comencé a encadenar desde allí:

La función de división de enteros Dutilizaba una serie de suma negada (sustracción en forma de A(x,A(~y,1)un bucle; el resto es manipulación de cadenas y concatenación para evitar el uso de +operadores de concatenación ...

El número debe proporcionarse en forma decimal con dos lugares decimales para que esto funcione ...

WallyWest
fuente
Ah, lo hará ahora ... aunque si tuviera que mantener las nuevas reglas, tendría que ampliarlo ... 251 bytes ahora ...
WallyWest
1

Perl 50 60 bytes

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

La entrada se espera en STDIN. Debe contener el separador decimal con dos dígitos decimales. La salida se escribe en STDOUT.

Actualización: el paso $_<<=1elimina los ceros a la izquierda. Por lo tantom|\d{3}$| lo , no coincidiría con las facturas <1. Por lo tanto, $_="00$se agregaron diez bytes , ahora incluso 0.00funciona.

Ejemplos:

  • Entrada: 20.96salida:4.19
  • Entrada: 12.34salida:2.47

Versión sin golf:

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

Primero se lee el número de STDIN. Luego se elimina el punto decimal, que se multiplica por 100. Luego, la cantidad se duplica por un operador de desplazamiento. Luego se reinserta el punto decimal y el resultado se imprime y se redondea a dos dígitos decimales.

50 bytes, si factura ≥ 1:

Si x.xxes mayor o igual que 1.00, entonces se pueden eliminar 10 bytes:

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

JavaScript (ES6) (Regex) 142

Regex es genial y puede hacer muchas cosas. ¡Incluso puede hacer matemáticas!

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

Versión legible:

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

los tip() función espera el argumento String, en lugar de Number.

Todas las instancias de *, /, +no están relacionados con las operaciones matemáticas.

  • + es la concatenación de cadenas en todos los casos en que se usa.
  • * es parte de la sintaxis RegExp
  • / es el delimitador del literal de RegExp

La entrada debe usarse .como punto decimal, y debe haber 2 dígitos después del punto decimal.

Fragmento de pila

<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̷̰̀ĥ̷̳
fuente
0

Haskell 32 caracteres -20% = 25.6 caracteres

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

Abusa del hecho de que los exponentes se convierten en multiplicación en logaritmos.

PyRulez
fuente