Zufriedenstellende Rundung

16

Zufriedenstellende Rundung

Sie wissen, wann Sie im Naturwissenschaftsunterricht sind, und haben gebeten, auf 2 Sig Feigen zu runden, aber Ihre Antwort lautet 5.2501...? Sie sollten sich zu runden 5.3, aber das ist einfach so unbefriedigend! Wenn Sie auf runden 5.3, haben Sie eine ganze Differenz von 0,05, was im Vergleich zu 0,1 (dem Stellenwert, auf den Sie runden) eine große Abweichung darstellt! Also hilf mir auf befriedigende Weise.

Um zufriedenstellend zu runden, müssen Sie an der ersten Stelle runden, die einen relativ kleinen Fehler verursacht - weniger als die Hälfte des maximal möglichen Rundungsfehlers. Grundsätzlich müssen Sie immer dann runden, wenn Sie auf 0, 1, 8 oder 9 stoßen. Wenn dies nicht der Fall ist, geben Sie die Eingabe wie sie ist zurück. Runden Sie nicht auf führende Nullen oder Einsen - das fühlt sich einfach nicht befriedigend an.

Eingang

Ein String oder Float-Wert, der eine nicht negative Dezimalzahl darstellt.

Ausgabe

Dieselbe Dezimalzahl wurde zufriedenstellend gerundet, entweder im Zeichenfolgen- oder im Gleitkommaformat.

Beispiele

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

Dies ist eine Herausforderung, also gewinnt der kürzeste Code!

Quintec
quelle
Sandbox
Quintec
Sind Zeichenfolgen wie 036.40000eine gültige Ausgabe?
Arnauld
1
Können wir davon ausgehen, dass ein .0Teil für ganze Zahlen angegeben wird? Auch 0ist nicht positiv.
Erik der Outgolfer
@EriktheOutgolfer Nein, du darfst nicht - auch danke, nicht negativ geändert.
Quintec
1
Also 19rundet auf 20aber 0.19rundet auf 0? Warum?
Neil

Antworten:

2

JavaScript (ES6),  100 99 98  78 Byte

Übernimmt die Eingabe als Zeichenfolge. Gibt ein float zurück.

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

Probieren Sie es online!

Wie?

Wir stellen der Eingabezeichenfolge zuerst eine führende 0 voran , damit wir garantiert eine Ziffer vor einer möglichen führenden 8 oder 9 haben, die die Rundung sofort auslösen muss.

Das Flag j wird auf 1 gesetzt, solange wir nach einer Ziffer suchen, auf die wir eine zufriedenstellende Rundung durchführen können, und anschließend auf 0 .

Da der Zeichenfolge, durch die wir gehen, eine führende 0 hinzugefügt wurde, s jedoch unverändert blieb, enthält d das aktuelle Zeichen und s[ich] zeigt auf das nächste Zeichen.

Wir verwenden den folgenden Code, um die nächste Ziffer in n zu laden , wobei ein mögliches Dezimaltrennzeichen übersprungen wird:

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

Obwohl Strings in JavaScript unveränderlich ist, der Ausdruck ++s[i]kehrt s[ich]+1 , wenn es einen numerischen Wert enthält, auch wenn s[ich] nicht tatsächlich erhöht. Daher wird der Ausdruck !++s[i]ausgewertet wird, um feinlse (dazu gezwungen zu 0 ) für alle Ziffern (einschließlich 0 ) und true (dazu gezwungen zu 1 ) für das Dezimalzeichen ".".

Wenn die Rundungs auftreten, ergeben wir , d + --jwenn die nächste Zahl n ist 0 oder 1 (und es ist nicht die führende Ziffer des ursprünglichen Eingangs) und d + j--wenn n ist 8 oder 9 . Deshalb,j00d1

Arnauld
quelle
1
Und der Flipper / Gummiball fällt in einen Graben! :)
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}

Probieren Sie es online!

Erläuterung

  • ->n Eingabe als String übernehmen
  • z=n+".0"Erstellen Sie eine temporäre Zeichenfolge z, die garantiert einen Punkt und eine relevante Ziffer enthält.
  • i=z=~/\./Bestimmen Sie die Position des Dezimalpunkts in zund weisen Sie zu i.
  • z[i]='' Lass den Punkt fallen, damit er dich nicht weiter stört.
  • z=~/(?!^)[01]|8|9/Bestimmen Sie die Position des Nichtstarters 0-1oder eines anderen 8-9, je nachdem, was zuerst eintritt.
  • (...)-i Diese Differenz ist die Anzahl der zu erhaltenden Dezimalstellen, negativ, wenn wir links vom Punkt abrunden.
  • n.to_f.round ... In Float umwandeln und runden.
Kirill L.
quelle
1

Jelly , 34 Bytes

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

Probieren Sie es online!

-1 Danke an Jonathan Allan .

Erik der Outgolfer
quelle
Warum ŒV? Ich denke, Vwird auch funktionieren.
Jonathan Allan
@ JonathanAllan Nope. (im Grunde Banker runden Macken)
Erik der Outgolfer
Oh, weil es nicht auf den Eingang wirkt? Versuchen Sie, _>¥0ɓVærwie meine ist (ich habe die Verwendung der dyadischen schnell verpasst, also danke auch!)
Jonathan Allan
@ JonathanAllan Ah, kluger Umgang mit Ketten, danke.
Erik der Outgolfer
1

Gelee ,  30  29 Bytes

-1 danke an Erik den Outgolfer (Verwendung von dyadic schnell ¥aus seiner Antwort)

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

Ein monadischer Link, der eine Liste von Zeichen akzeptiert, die ein Float ergibt.

Probieren Sie es online! Oder schauen Sie sich die Testsuite an .

Wie

Beachten Sie zunächst, dass die Eingabezeichenfolge ausschließlich aus den Zeichen besteht 0123456789., die Ordnungszahlen haben [48,49,50,51,52,53,54,55,56,57,46], die Restzeichen enthalten , wenn sie durch acht von geteilt werden [0,1,2,3,4,5,6,7,0,1,6]. Die einzigen Zeichen , die zwischen sind -1und 1sind inklusive 0, 1, 8, und 9.

Wenn wir außerdem acht von den Ordnungszahlen ( [40,41,42,43,44,45,46,47,48,49,38]) abziehen, gilt dasselbe (ziemlich offensichtlich). Wenn wir diese ( [20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19]) halbieren, sind und die einzigen Zeichen, die bei Division durch acht Restzeichen haben, die zwischen -1und 1einschließlich liegen .89

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

Retina 0.8.2 , 75 Bytes

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

Probieren Sie es online! Link enthält Testfälle. Erläuterung:

^[89]
10

Behandeln Sie den Fall eines führenden 8oder 9.

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

Wenn es ein nicht führendes 0oder gibt 1, dann nullen Sie es und den Rest der Zeichenfolge aus. Auch wenn es ein 8oder gibt 9, lassen Sie es, aber setzen Sie den Rest der Zeichenfolge auf Null. (Lassen Sie den Dezimalpunkt jedoch in beiden Fällen unverändert.)

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

Wenn zu diesem Zeitpunkt noch ein 8oder ein vorhanden 9ist, setzen Sie es auf Null und erhöhen Sie die vorherige Ziffer (möglicherweise vor dem Dezimalpunkt).

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

Löschen Sie nachfolgende Nullen, wenn sie nach einem Dezimalpunkt liegen, aber löschen Sie den Dezimalpunkt nur, wenn keine anderen Ziffern dazwischen stehen.

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

Probieren Sie es 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
quelle
0

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

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

Probieren Sie es online!

Es kann kürzer sein, wenn ich Doppelte anstelle von Dezimalstellen verwendet habe, aber ich habe Dezimalstellen verwendet, um die Genauigkeit zu erhalten, oder eine Zahl wie 547.4726 wäre 547.472595214844.

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

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

Probieren Sie es online aus! (Weniger genaue Version)

Verkörperung der Ignoranz
quelle