Redondeo satisfactorio

16

Redondeo satisfactorio

Sabes cuando estás en la clase de ciencias y te piden redondear a 2 higos, pero tu respuesta es 5.2501...? Deberías redondear a 5.3, ¡pero eso es tan insatisfactorio! Al redondear a 5.3, se obtiene un total de 0.05, que es una gran cantidad en comparación con 0.1 (el valor posicional al que está redondeando). Así que ayúdame a redondear de una manera satisfactoria.

Para redondear de manera satisfactoria, debe redondear en el primer dígito que encuentre que produce un error relativamente pequeño, menos de la mitad del error máximo posible al redondear. Básicamente, debe redondear cada vez que encuentre 0, 1, 8 o 9. Si eso nunca sucede, devuelva la entrada como está. No redondee los ceros a la izquierda o unos, eso simplemente no se siente satisfactorio.

Entrada

Una cadena o valor flotante que representa un número decimal no negativo.

Salida

El mismo número decimal redondeado satisfactoriamente, en formato de cadena o flotante.

Ejemplos

Input -> Output
0 -> 0
0.5 -> 0.5
0.19 -> 0
0.8 -> 1
5.64511 -> 5.645
18.913 -> 20
88.913 -> 100
36.38299 -> 36.4
621 -> 620
803.22 -> 1000
547.4726 -> 547.4726

Este es un desafío de , por lo que gana el código más corto.

Quintec
fuente
Sandbox
Quintec
¿Se 036.40000consideran cadenas como una salida válida?
Arnauld
1
¿Podemos suponer que se .0dará una parte para enteros? Además, 0no es positivo.
Erik the Outgolfer
@EriktheOutgolfer No, puede que no, también gracias, cambie a no negativo.
Quintec
1
¿Entonces 19redondea 20pero 0.19redondea 0? ¿Por qué?
Neil

Respuestas:

2

JavaScript (ES6),  100 99 98  78 bytes

Toma la entrada como una cadena. Devuelve un flotador.

s=>+(0+s).replace(/\d/g,(d,i)=>j&&+d+((n=s[i+!++s[i]])<2&&i?--j:n>7&&j--),j=1)

Pruébalo en línea!

¿Cómo?

Primero anteponemos un 0 0 inicial a la cadena de entrada, para garantizar que tengamos un dígito antes de un posible 8 o 9 9 , que debe activar el redondeo de inmediato.

La bandera j se establece en 1 siempre que estemos buscando un dígito en el que podamos realizar un redondeo satisfactorio, y luego se establece en 0 0 .

Debido a que se agregó un 0 0 inicial a la cadena por la que estamos caminando pero s se modificó, re contiene el carácter actual y s[yo] apunta al siguiente carácter.

Usamos el siguiente código para cargar el siguiente dígito en norte , omitiendo un posible separador decimal:

n = s[i + !++s[i]]

Aunque las cadenas son inmutables en JavaScript, la expresión ++s[i]devolverá s[yo]+1 si contiene un valor numérico, aunque s[yo] no se incremente realmente. Por lo tanto, la expresión !++s[i]se evalúa como Funlsmi (forzada a 0 0 ) para todos los dígitos (incluido 0 0 ) y a trtumi (forzada a 1 ) para el separador decimal ".".

Cuando se produce el redondeo, producimos d + --jsi el siguiente dígito norte es 0 0 o 1 (y no es el dígito inicial de la entrada original) y d + j--si norte es 8 o 9 9 . Por lo tanto, j se establece en 0 0 en ambos casos, pero agregamos 0 0 a re en el primer caso (redondeando hacia abajo) y 1 en el segundo caso (redondeando hacia arriba).

Arnauld
fuente
1
¡Y la bola de pinball / goma cae en una zanja! :)
Quintec
2

Rubí , 79 77 69 67 65 bytes

->n,z=n+".0"{z[i=z=~/\./]='';n.to_f.round (z=~/(?!^)[01]|8|9/)-i}

Pruébalo en línea!

Explicación

  • ->n Tomar entrada como una cadena
  • z=n+".0"Cree una cadena temporal zque garantice que contiene un punto y un dígito relevante.
  • i=z=~/\./Determine la posición del punto decimal zy asigne a i.
  • z[i]='' Suelta el punto para que no se interponga más adelante.
  • z=~/(?!^)[01]|8|9/Determine la posición de no arranque 0-1o cualquiera 8-9, lo que ocurra primero.
  • (...)-i Esta diferencia será el número de decimales para mantener, negativo si redondearemos a la izquierda del punto.
  • n.to_f.round ... Convierte a flotador y haz el redondeo.
Kirill L.
fuente
1

Jalea , 34 bytes

;”.ḟ$µ»"”2e€⁽¡XṾ¤;1i1_i”.$_>¥0ɓVær

Pruébalo en línea!

-1 gracias a Jonathan Allan .

Erik el Outgolfer
fuente
¿Por qué ŒV? Creo que Vtambién funcionará.
Jonathan Allan
@JonathanAllan Nope. (básicamente caprichos de redondeo del banquero)
Erik the Outgolfer
Oh, porque no está actuando en la entrada? Intenta _>¥0ɓVærcomo el mío (perdí el uso de la diádica rápida, ¡así que gracias también!)
Jonathan Allan
@ JonathanAllan Ah, uso inteligente de las cadenas, gracias.
Erik the Outgolfer
1

Gelatina ,  30  29 bytes

-1 gracias a Erik the Outgolfer (uso de dyadic quick ¥de su respuesta)

O;0µ_8H1¦%8ỊTḢ_<48TḢƊ_>¥0ɓVær

Un enlace monádico que acepta una lista de caracteres que produce un flotante.

Pruébalo en línea! O ver el conjunto de pruebas .

Cómo

Primero tenga en cuenta que la cadena de entrada está hecha exclusivamente de los caracteres 0123456789.que tienen ordinales [48,49,50,51,52,53,54,55,56,57,46], que tienen restos cuando se divide por ocho de [0,1,2,3,4,5,6,7,0,1,6]. Los únicos personajes que están entre -1e 1inclusivo son 0, 1, 8, y9 .

Además, si restamos ocho de los ordinales ( [40,41,42,43,44,45,46,47,48,49,38]), lo mismo (bastante obvio) es válido. Si dividimos a la mitad estos ( [20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19]), los únicos caracteres que tienen restos cuando se dividen entre ocho, que están entre -1e 1inclusive, son 8y 9.

O;0µ_8H1¦%8ỊTḢ_<48TḢƊ_>¥0ɓVær - Link: list of characters, S
O                             - ordinal (vectorises across S)
 ;0                           - concatenate a zero
                              - (to cater BOTH for no '0', '1', '8', or '9' AND for no '.')
   µ                          - start a new monadic link (call that X)
    _8                        - subtract eight (vectorises across X)
        ¦                     - sparse application...
       1                      - ...to: indices: one
      H                       - ...do: halve (i.e. halve first ordinal)
         %8                   - modulo by eight (vectorises)
           Ị                  - insignificant (abs(v)<=1?) (vectorises)
            T                 - truthy indices
             Ḣ                - head
                    Ɗ         - last three links as a monad (i.e. f(X)):
               <48            -   less than 48? (i.e. was it a '.' in S or the added 0?)
                  T           -   truthy indices
                   Ḣ          -   head
              _               - subtract
                       ¥      - last two links as a dyad
                      < 0     -   less than zero? (1 if so 0 otherwise)
                     _        -   subtract
                         ɓ    - start a new dyadic chain (i.e. f(S,X))
                          V   - evaluate S as Jelly code (i.e. get S as a float)
                           ær - round to the nearest multiple of 10^(-X)
Jonathan Allan
fuente
1

Retina 0.8.2 , 75 bytes

^[89]
10
T`d`0`(?<=.)[01].*|(?<=8|9).*
T`89d`0d`.\.?[89]
(\.|(\..+?))0+$
$2

Pruébalo en línea! El enlace incluye casos de prueba. Explicación:

^[89]
10

Manejar el caso de un líder 8o 9.

T`d`0`(?<=.)[01].*|(?<=8|9).*

Si hay un no líder 0o 1, entonces ponlo a cero y el resto de la cadena. Además, si hay un 8o 9, déjelo, pero ponga a cero el resto de la cadena. (Pero deje el punto decimal sin cambios en cualquier caso).

T`89d`0d`.\.?[89]

Si todavía hay un 8o a 9en este punto, ponlo a cero e incrementa el dígito anterior (posiblemente antes del punto decimal).

(\.|(\..+?))0+$
$2

Elimine los ceros finales si van después de un punto decimal, pero solo elimine el punto decimal si no hay otros dígitos intermedios.

Neil
fuente
1

C (gcc) , 111 102 bytes

g(_,i,j,k)char*_;{for(i=*_<56?*_++:48,j=3;j;j&=k%8>1|(i=*_++)/48*2)putchar(j&1?i+(k=_[*_<48])/56:48);}

Pruébalo en línea!

//_: input, as string
//i: current digit, rounded if applicable
//j: tracks whether number is rounded, and whether \0 or '.' has been encountered
//k: digit to test rounding (round if k is one of 0,1,8,9)
//'0'==48, '8'==56
g(_,i,j,k)char*_;{
    for(i=*_<56?*_++:48,j=3;                //special case: if first digit is 8 or 9, use a
                                            //placeholder digit with value 0. initialize j.
        j;                                  //only stop execution when number is rounded and
                                            //'.' or \0 has been encountered.
        j&=k%8>1|(i=*_++)/48*2)             //check if execution should stop.
        putchar(j&1?i+(k=_[*_<48])/56:48);  //print '0' if rounding had already been done;
                                            //otherwise, print digit. round up as needed.
}
attinat
fuente
0

C # (compilador interactivo de Visual C #) , 280 bytes

c=>{int d=c.IndexOf('.');int t=c.IndexOfAny(new char[]{'8','9','0','1'},1);var m=c[0]=='8'||c[0]=='9'?1>0:0>1;var z=decimal.Parse(c);Func<decimal>q=()=>(decimal)Math.Pow(10,m?d<0?c.Length:d:d<0?c.Length-t:d>t?d-t:d-t+1);return m?Math.Round(z/q())*q():t<0?z:Math.Round(z/q())*q();}

Pruébalo en línea!

Puede ser más corto si usé dobles en lugar de decimales, pero usé decimales para preservar la precisión, o de lo contrario un número como 547.4726 sería 547.472595214844.

C # (compilador interactivo de Visual C #) , 268 bytes

c=>{int d=c.IndexOf('.');int t=c.IndexOfAny(new char[]{'8','9','0','1'},1);var m=c[0]=='8'||c[0]=='9'?1>0:0>1;var z=float.Parse(c);Func<double>q=()=>Math.Pow(10,m?d<0?c.Length:d:d<0?c.Length-t:d>t?d-t:d-t+1);return m?Math.Round(z/q())*q():t<0?z:Math.Round(z/q())*q();}

Pruébelo en línea (versión menos precisa)

Encarnación de la ignorancia
fuente