Arredondamento satisfatório

16

Arredondamento satisfatório

Você sabe quando está na aula de ciências e pediu para arredondar para 2 sig figs, mas a sua resposta é 5.2501...? Você deve arredondar para 5.3, mas isso é tão insatisfatório! Ao arredondar para 5.3, você sai com 0,05, o que é uma grande quantia em comparação com 0,1 (o valor do local para o qual você está arredondando)! Então me ajude de uma maneira satisfatória.

Para arredondar de maneira satisfatória, você deve arredondar no primeiro dígito que encontrar, que produz um erro relativamente pequeno - menos da metade do erro máximo possível ao arredondar. Basicamente, você precisa arredondar sempre que encontrar 0, 1, 8 ou 9. Se isso nunca acontecer, retorne a entrada como está. Não use zeros à esquerda ou zeros - isso simplesmente não parece satisfatório.

Entrada

Um valor de sequência ou flutuante que representa um número decimal não negativo.

Resultado

O mesmo número decimal arredondado satisfatoriamente, no formato string ou float.

Exemplos

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 é um desafio do , pelo que o código mais curto vence!

Quintec
fonte
Sandbox
Quintec
As seqüências de caracteres são 036.40000consideradas uma saída válida?
Arnauld
1
Podemos assumir que uma .0parte será dada para números inteiros? Além disso, 0não é positivo.
Erik the Outgolfer
@EriktheOutgolfer Não, você não pode - também obrigado, alterado para não-negativo.
Quintec 8/12
1
Então, 19volta para, 20mas 0.19volta para 0? Por quê?
Neil

Respostas:

2

JavaScript (ES6),  100 99 98  78 bytes

Recebe a entrada como uma sequência. Retorna um flutuador.

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

Experimente online!

Quão?

Primeiro, adicionamos um 0 0 à sequência de entrada, para garantir um dígito antes de um possível 8 ou 9 , que deve acionar o arredondamento imediatamente.

O sinalizador j é definido como 1 , desde que procuremos um dígito no qual possamos fazer um arredondamento satisfatório e definido como 0 0 depois.

Como um 0 0 foi adicionado à string pela qual estamos caminhando, mas s foi deixado inalterado, d contém o caractere atual s[Eu] está apontando para o próximo caractere.

Usamos o código a seguir para carregar o próximo dígito em n , ignorando um possível separador decimal:

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

Embora as strings sejam imutáveis ​​no JavaScript, a expressão ++s[i]retornará s[Eu]+1 se contiver um valor numérico, mesmo que s[Eu] não seja realmente incrementado. Portanto, a expressão !++s[i]é avaliada para fumaeuse (forçado a 0 0 ) para todos os dígitos (incluindo 0 0 ) e a trvocêe (forçado a 1 ) para o separador decimal ".".

Quando o arredondamento ocorre, produzimos d + --jse o próximo dígito n for 0 0 ou 1 (e não for o dígito inicial da entrada original) e d + j--se n89j0 00 0d1

Arnauld
fonte
1
E a bola de pinball / borracha cai em uma vala! :)
Quintec
2

Ruby , 79 77 69 67 65 bytes

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

Experimente online!

Explicação

  • ->n Receber entrada como uma string
  • z=n+".0"Crie uma sequência temporária zque garanta que contenha um ponto e um dígito relevante.
  • i=z=~/\./Determine a posição do ponto decimal ze atribua a i.
  • z[i]='' Solte o ponto para que ele não atrapalhe ainda mais.
  • z=~/(?!^)[01]|8|9/Determine a posição de não partida 0-1ou qualquer 8-9, o que ocorrer primeiro.
  • (...)-i Essa diferença será o número de casas decimais a manter, negativo se arredondarmos para a esquerda do ponto.
  • n.to_f.round ... Converta para flutuar e faça o arredondamento.
Kirill L.
fonte
1

Geléia , 34 bytes

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

Experimente online!

-1 graças a Jonathan Allan .

Erik, o Outgolfer
fonte
Por que ŒV? Eu acho que Vvai funcionar também.
Jonathan Allan
@JonathanAllan Nope. (basicamente as peculiaridades dos banqueiros)
Erik the Outgolfer 08/12/19
Ah, porque não está agindo na entrada? Tente _>¥0ɓVærcomo o meu é (eu perdi o uso da rápida dyadic por isso obrigado também!)
Jonathan Allan
@ JonathanAllan Ah, uso inteligente de cadeias, obrigado.
Erik the Outgolfer
1

Geléia ,  30  29 bytes

-1 graças a Erik, o Outgolfer (uso rápido diádico ¥de sua resposta)

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

Um link monádico que aceita uma lista de caracteres que produz um float.

Experimente online! Ou veja a suíte de testes .

Quão

Primeiro, observe que a sequência de entrada é composta exclusivamente dos caracteres 0123456789.que têm ordinais [48,49,50,51,52,53,54,55,56,57,46], que têm restos quando divididos por oito [0,1,2,3,4,5,6,7,0,1,6]. Os únicos personagens que são entre -1e 1inclusiva são 0, 1, 8, e 9.

Além disso, se subtrairmos oito dos ordinais ( [40,41,42,43,44,45,46,47,48,49,38]), o mesmo (obviamente) é válido. Se dividirmos pela metade esses ( [20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19]), os únicos caracteres que têm remanescentes quando divididos por oito que estão entre -1e 1inclusive são 8e 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
fonte
1

Retina 0.8.2 , 75 bytes

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

Experimente online! O link inclui casos de teste. Explicação:

^[89]
10

Lidar com o caso de um líder 8ou 9.

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

Se houver um não-líder 0ou 1, zere-o e o restante da string. Além disso, se houver um 8ou 9, deixe-o, mas zere o restante da string. (Mas mantenha o ponto decimal inalterado em ambos os casos.)

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

Se ainda houver um 8ou 9a nesse ponto, zere-o e aumente o dígito anterior (possivelmente antes do ponto decimal).

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

Exclua zeros à direita se estiverem após um ponto decimal, mas exclua apenas o ponto decimal se não houver outros dígitos no meio.

Neil
fonte
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);}

Experimente online!

//_: 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
fonte
0

C # (compilador interativo do 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();}

Experimente online!

Pode ser mais curto se eu usei duplas em vez de decimais, mas usei decimais para preservar a precisão; caso contrário, um número como 547.4726 seria 547.472595214844.

C # (compilador interativo do 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();}

Experimente online! (Versão menos precisa)

Modalidade de ignorância
fonte