Arrondi satisfaisant


16

Arrondi satisfaisant

Vous savez quand vous êtes en cours de science et que vous avez demandé d'arrondir à 2 figues sig, mais votre réponse est 5.2501...? Vous devriez arrondir à 5.3, mais c'est tellement insatisfaisant! En arrondissant à5.3 , vous avez un total de 0,05, ce qui est une grande quantité par rapport à 0,1 (la valeur de position à laquelle vous arrondissez)! Alors aidez-moi à tourner de manière satisfaisante.

Pour arrondir de manière satisfaisante, vous devez arrondir au premier chiffre que vous rencontrez, ce qui produit une erreur relativement faible - moins de la moitié de l'erreur maximale possible lors de l'arrondi. Fondamentalement, vous devez arrondir chaque fois que vous rencontrez 0, 1, 8 ou 9. Si cela ne se produit jamais, renvoyez l'entrée telle quelle. N'arrondissez pas les zéros ou les uns au début - cela ne semble tout simplement pas satisfaisant.

Contribution

Une chaîne ou une valeur flottante qui représente un nombre décimal non négatif.

Production

Le même nombre décimal arrondi de manière satisfaisante, au format chaîne ou flottant.

Exemples

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

C'est un défi de , donc le code le plus court gagne!



Les chaînes telles que 036.40000considérées comme une sortie valide?
Arnauld

1
Peut-on supposer qu'une .0partie sera donnée pour les entiers? De plus, ce 0n'est pas positif.
Erik the Outgolfer

@EriktheOutgolfer Non, vous ne pouvez pas - aussi merci, changé en non négatif.
Quintec

1
Donc, 19arrondit à 20mais 0.19arrondit à 0? Pourquoi?
Neil

Réponses:


2

JavaScript (ES6),  100 99 98  78 octets

Prend l'entrée sous forme de chaîne. Renvoie un flottant.

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

Essayez-le en ligne!

Comment?

Nous ajoutons d'abord un 0 de début à la chaîne d'entrée, de sorte que nous sommes garantis d'avoir un chiffre avant un 8 ou 9 de début possible.9 , qui doit immédiatement déclencher l'arrondi.

Le drapeau j est mis à 1 tant que nous recherchons un chiffre sur lequel nous pouvons effectuer un arrondi satisfaisant, et mis à 0 par la suite.

Parce qu'un 0 tête a été ajouté à la chaîne que nous parcourons mais que s est resté inchangé, d contient le caractère actuel et s[i] pointe vers le caractère suivant .

Nous utilisons le code suivant pour charger le chiffre suivant dans n , en sautant un séparateur décimal possible:

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

Bien que les chaînes soient immuables en JavaScript, l'expression ++s[i]renverra s[i]+1 si elle contient une valeur numérique, même si s[i] n'est pas réellement incrémenté. Par conséquent, l'expression !++s[i]est évaluée à false (contraint à 0 ) pour tous les chiffres (y compris 0 ) et à true (contraint à 1 ) pour le séparateur décimal ".".

d + --jn01d + j--n89j00d1


1
Et le flipper / balle en caoutchouc tombe dans un fossé! :)
Quintec

2

Rubis , 79 77 69 67 65 octets

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

Essayez-le en ligne!

Explication

  • ->n Prendre l'entrée comme une chaîne
  • z=n+".0" Créer une chaîne temporaire z qui est garantie de contenir un point et un chiffre pertinent.
  • i=z=~/\./Déterminez la position du point décimal zet attribuez-le ài .
  • z[i]='' Déposez le point pour qu'il ne gêne pas plus loin.
  • z=~/(?!^)[01]|8|9/Déterminer la position de non-départ 0-1ou de tout8-9 événement, selon la première éventualité.
  • (...)-i Cette différence sera le nombre de décimales à conserver, négatif si nous arrondissons à gauche du point.
  • n.to_f.round ... Convertissez pour flotter et arrondissez.

1

Gelée , 34 octets

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

Essayez-le en ligne!

-1 merci à Jonathan Allan .


Pourquoi ŒV? Je pense que ça Vmarchera aussi.
Jonathan Allan

@JonathanAllan Nope. (essentiellement des caprices d'arrondi de banquier)
Erik the Outgolfer

Oh, parce que ça n'agit pas sur l'entrée? Essayez _>¥0ɓVærcomme le mien (j'ai manqué l'utilisation du rapide dyadique alors merci aussi!)
Jonathan Allan

@JonathanAllan Ah, utilisation intelligente des chaînes, merci.
Erik the Outgolfer

1

Gelée ,  30  29 octets

-1 merci à Erik l'Outgolfer (utilisation rapide de dyadique ¥de sa réponse)

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

Un lien monadique acceptant une liste de caractères qui donne un flottant.

Essayez-le en ligne! Ou voir le suite de tests .

Comment

Notez d'abord que la chaîne d'entrée est composée exclusivement de caractères 0123456789.qui ont des ordinaux [48,49,50,51,52,53,54,55,56,57,46], qui ont des restes lorsqu'ils sont divisés par huit [0,1,2,3,4,5,6,7,0,1,6]. Les seuls caractères qui sont entre -1et 1comprennent 0, 1, 8et 9.

De plus, si l'on soustrait huit des ordinaux ( [40,41,42,43,44,45,46,47,48,49,38]), la même chose (assez évidemment) est vraie. Si nous divisons par deux ces ( [20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19]) les seuls caractères qui ont des restes lorsqu'ils sont divisés par huit qui sont entre -1et 1inclusifs sont 8et 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)

1

Retina 0.8.2 , 75 octets

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

Essayez-le en ligne! Le lien inclut des cas de test. Explication:

^[89]
10

Gérer le cas d'un interligne 8ou 9.

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

S'il y a un non-leader 0ou 1, puis zéro et le reste de la ficelle. De plus, s'il y a un 8ou 9, laissez-le, mais mettez à zéro le reste de la chaîne. (Mais laissez le point décimal inchangé dans les deux cas.)

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

S'il y a encore un 8ou un 9à ce point, mettez-le à zéro et incrémentez le chiffre précédent (éventuellement avant le point décimal).

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

Supprimez les zéros de fin s'ils se trouvent après un point décimal, mais supprimez le point décimal uniquement s'il n'y a pas d'autres chiffres entre les deux.


1

C (gcc) , 111 102 octets

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

Essayez-le en ligne!

//_: 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.
}

0

C # (Visual C # Interactive Compiler) , 280 octets

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

Essayez-le en ligne!

Il peut être plus court si j'utilise des doubles au lieu de décimales, mais j'utilise des décimales pour préserver la précision, sinon un nombre comme 547.4726 serait 547.472595214844.

C # (Visual C # Interactive Compiler) , 268 octets

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

Essayez-le en ligne! (Version moins précise)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.