Rund um die Schnur

10

Einige Dezimalzahlen können aufgrund der internen Darstellung der binären Gleitkommazahlen nicht genau als binäre Gleitkommazahlen dargestellt werden. Beispiel: Das Runden von 14.225 auf zwei Dezimalstellen führt nicht wie erwartet zu 14.23, sondern zu 14.22.

Python :

In: round(14.225, 2)
Out: 14.22

Angenommen, wir haben eine Zeichenfolgendarstellung von 14.225 als '14 .225 ', dann sollten wir in der Lage sein, unsere gewünschte Rundung '14 .23' als Zeichenfolgendarstellung zu erreichen.

Dieser Ansatz kann mit beliebiger Genauigkeit verallgemeinert werden.

Mögliche Python 2/3 Lösung

import sys

def round_string(string, precision):
    assert(int(precision) >= 0)
    float(string)

    decimal_point = string.find('.')
    if decimal_point == -1:
        if precision == 0:
            return string
        return string + '.' + '0' * precision

    all_decimals = string[decimal_point+1:]
    nb_missing_decimals = precision - len(all_decimals)
    if nb_missing_decimals >= 0:
        if precision == 0:
            return string[:decimal_point]
        return string + '0' * nb_missing_decimals

    if int(all_decimals[precision]) < 5:
        if precision == 0:
            return string[:decimal_point]
        return string[:decimal_point+precision+1]

    sign = '-' if string[0] == '-' else '' 
    integer_part = abs(int(string[:decimal_point]))
    if precision == 0:
        return sign + str(integer_part + 1)
    decimals = str(int(all_decimals[:precision]) + 1)
    nb_missing_decimals = precision - len(decimals)
    if nb_missing_decimals >= 0:
        return sign + str(integer_part) + '.' + '0' * nb_missing_decimals + decimals
    return sign + str(integer_part + 1) + '.' + '0' * precision

Probieren Sie es online aus!

Verwendung :

     # No IEEE 754 format rounding
In:  round_string('14.225',2)
Out: '14.23'

     # Trailing zeros
In:  round_string('123.4',5)
Out: '123.40000'

In: round_string('99.9',0)
Out: '100'

    # Negative values
In: round_string('-99.9',0)
Out: '-100'

In: round_string('1',0)
Out: '1'

    # No unnecessary decimal point
In: round_string('1.',0)
Out: '1'

    # No unnecessary decimal point
In: round_string('1.0',0)
Out: '1'

In:  for i in range(8): 
         print(round_string('123456789.987654321',i))
Out: 123456790
     123456790.0
     123456789.99
     123456789.988
     123456789.9877
     123456789.98765
     123456789.987654
     123456789.9876543

Aufgabe

Eingabeargument 1 : Eine Zeichenfolge, die enthält

  • mindestens eine Ziffer ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
  • höchstens ein Dezimalpunkt ( .), dem mindestens eine Ziffer vorangestellt sein muss,
  • ein optionales Minuszeichen ( -) als erstes Zeichen.

Eingabeargument 2 : eine nicht negative Ganzzahl

Ausgabe : Die korrekt gerundete Zeichenfolge (Basis 10)

Rundung = Runde halb weg von Null

Dies ist ein . Die niedrigste Anzahl von Bytes gewinnt!

Matthias
quelle
@ KevinCruijssen 1) Sie müssen sich nicht an Zeichenfolgen im Hauptteil Ihrer Implementierung halten und dürfen die integrierte Rundung verwenden. Leider (für die Frage) ist der IEEE 754-Standard ein weit verbreiteter Standard, und daher führt die integrierte Rundung nicht zum gewünschten Verhalten. 2) Ok, war mir des Sandkastens nicht bewusst.
Matthias
TI-Basic: round(A,B5 Bytes
Julian Lachniet
1
In Bezug auf das zweite Eingabeargument: 0ist keine positive Ganzzahl, sondern "nicht negativ".
Stewie Griffin
1
Ich nehme an, wir fügen bei Bedarf nachgestellte Nullen hinzu. Könnten Sie vielleicht einen Testfall für hinzufügen 123.4 & 5 --> 123.40000? Oder können wir davon ausgehen, dass die zweite Eingabe niemals größer sein wird als die Anzahl der Dezimalstellen nach dem Punkt in der ersten Eingabe?
Kevin Cruijssen
1
@Matthias Es sei denn, Sie können Python in JavaScript integrieren (ich habe Python noch nie programmiert und kaum JS, daher weiß ich ehrlich gesagt nicht, ob es möglich ist). Sie können jedoch jederzeit einen Online- Link zum Testen mit Ihrem Testcode hinzufügen . EDIT: Außerdem ist es normalerweise besser, mindestens ein paar Tage zu warten, bis Sie eine Antwort akzeptieren.
Kevin Cruijssen

Antworten:

2

APL (Dyalog) , 4 Bytes

Dyalog APL verwendet genügend interne Präzision.

⎕⍕⍎⍞

Probieren Sie es online aus!

⍎⍞ String-Eingabe ausführen

⎕⍕ Holen Sie sich numerische Eingaben und verwenden Sie diese als Genauigkeit für die Formatierung

Adam
quelle
Warum ist das 4 statt 8 Bytes?
Matthias
@ Matthias Weil Dyalog APL eine SBCS hat
Adám
5

Perl, 22 20 Bytes

printf"%.*f",pop,pop

Verwenden von:

perl -e 'printf"%.*f",pop,pop' 123456789.987654321 3

Es ist Dadas Version des Codes. Bisherige:

printf"%*2\$.*f",@ARGV
Denis Ibaev
quelle
2
printf"%.*f",pop,popsollte funktionieren
Dada
5

PHP, 33 31 Bytes

PHP rundet auch richtig (mindestens auf 64 Bit):

printf("%.$argv[2]f",$argv[1]);

Nimmt Eingaben von Befehlszeilenargumenten entgegen. Laufen Sie mit -r.

PHP, keine eingebauten, 133 Bytes

[,$n,$r]=$argv;if($p=strpos(_.$n,46))for($d=$n[$p+=$r],$n=substr($n,0,$p-!$r);$d>4;$n[$p]=(5+$d=$n[$p]-4)%10)$p-=$n[--$p]<"/";echo$n;

Laufen Sie mit -nroder testen Sie es online .

Nervenzusammenbruch

[,$n,$r]=$argv;             // import arguments
if($p=strpos(_.$n,46))      // if number contains dot
    for($d=$n[$p+=$r],          // 1. $d= ($r+1)-th decimal 
        $n=substr($n,0,$p-!$r); // 2. cut everything behind $r-th decimal
        $d>4;                   // 3. loop while previous decimal needs increment
        $n[$p]=(5+$d=$n[$p]-4)%10   // B. $d=current digit-4, increment current digit
    )
        $p-=$n[--$p]<"/";           // A. move cursor left, skip dot
echo$n;

Ein Null-Byte funktioniert nicht. also muss ich verwenden substr.

Titus
quelle
1
Sie können "%.$argv[2]f"stattdessen schreiben "%.{$argv[2]}f"und dabei 2 Bytes sparen.
Ismael Miguel
4

Ruby 2.3, 12 + 45 = 57

Verwendet das BigDecimaleingebaute Gerät , muss jedoch vor dem Gebrauch benötigt werden, was als Flagge billiger ist.

die Flagge: -rbigdecimal

die Funktion:

->(s,i){BigDecimal.new(s).round(i).to_s('f')}

Ruby 2.3 verwendet standardmäßig ROUND_HALF_UP

SztupY
quelle
4

Javascript (ES6), 44 Bytes

n=>p=>(Math.round(n*10**p)/10**p).toFixed(p)

Probieren Sie es online aus:

const f = n=>p=>(Math.round(n*10**p)/10**p).toFixed(p)

console.log(f('14.225')(2));

[...Array(8).keys()].map(i=>console.log(f('123456789.987654321')(i)))

console.log(f('123.4')(5))

powelles
quelle
4

Python, 114 105 103 96 91 89 Bytes

5 Bytes dank Kevin Cruijssen
gespeichert 2 Bytes dank Krazor gespeichert

from decimal import*
d=Decimal
lambda x,y:d(x).quantize(d('0.'[y>0]+'1'*y),ROUND_HALF_UP)

Probieren Sie es online aus!

Emigna
quelle
1
from decimal import *und das Entfernen der drei d.ist 4 Bytes kürzer.
Kevin Cruijssen
@ KevinCruijssen: Danke!
Emigna
2
Sie könnten auch tun d=Decimalund d() , was weitere 5 retten würde. (
Könnte
@ Krazor: Wenn ich es nicht falsch gemacht habe, habe ich 2 Bytes gespart. Vielen Dank!
Emigna
Woops, das habe ich gemeint. Werde meine schläfrigen Gedanken sowieso verlassen.
FMaz
4

REXX, 24 Bytes

arg n p
say format(n,,p)

Da REXX immer die Textdarstellung von Zahlen verwendet, ist die korrekte Rundung von Zahlen kostenlos.

Probieren Sie es online aus!

Idrougge
quelle
Beeindruckend. netter Missbrauch der Sprache.
Matthew Roh
Hat REXX einen Online-Compiler?
Kevin Cruijssen
Es ist (hauptsächlich) eine interpretierte Sprache.
Idrougge
3

BASH, 26 23 21 Bytes

bc<<<"scale=$2;$1/1"

Verwendungszweck

Speichern Sie in round_string.sh, chmod + x round_string.sh

./round_string.sh 23456789.987654321 3

Bearbeiten: Bibliothek muss nicht geladen werden

Markosmos
quelle
Erläuterung: bc verwendet eine willkürliche Präzision. Erstellen Sie hier ein Dokument mit '<<<', das den Wert der Skala als zweiten Parameter und den ersten Parameter geteilt durch 1 enthält, um die Interpretation der Skala zu erzwingen.
Marcosm
2
Dies gibt 14.22für die Eingabe 14.225 2und nicht14.23
Digital Trauma
3

AHK, 25 Bytes

a=%1%
Send % Round(a,%2%)

Ich bin wieder vereitelt von der Unfähigkeit von AHK, übergebene Parameter direkt in Funktionen zu verwenden, die entweder einen Variablennamen oder eine Zahl akzeptieren. Wenn ich ersetzen amit 1der RoundFunktion, verwendet es den Wert 1. Wenn ich es versuche %1%, wird versucht, den Inhalt des ersten Arguments als Variablennamen zu verwenden, was nicht funktioniert. Das Festlegen einer anderen Variablen kostete mich zuerst 6 Bytes.

Ingenieur Toast
quelle
3

Stapel, 390 Bytes

@echo off
set s=%1
set m=
if %s:~,1%==- set m=-&set s=%s:~1%
set d=%s:*.=%
if %d%==%s% (set d=)else call set s=%%s:.%d%=%%
for /l %%i in (0,1,%2)do call set d=%%d%%0
call set/ac=%%d:~%2,1%%/5
call set d=00%s%%%d:~,%2%%
set z=
:l
set/ac+=%d:~-1%
set d=%d:~,-1%
if %c%==10 set c=1&set z=%z%0&goto l
set d=%m%%d:~2%%c%%z%
if %2==0 (echo %d%)else call echo %%d:~,-%2%%.%%d:~-%2%%

Erläuterung. Beginnt gegebenenfalls mit dem Extrahieren des Zeichens. Teilt dann die Zahl in Ganzzahl- und Bruchziffern auf. Der Bruch wird mit n+1Nullen aufgefüllt, um sicherzustellen, dass er mehr als nZiffern enthält. Die ndritte (nullindizierte) Ziffer wird durch 5 geteilt, und dies ist der anfängliche Übertrag. Die Ganzzahl- und nBruchziffern werden verkettet und der Übertrag zeichenweise hinzugefügt. (Die zusätzlichen Nullen schützen vor Übertragswelligkeit.) Nachdem die Übertragswelligkeit aufhört, wird die Zahl rekonstruiert und ein Dezimalpunkt eingefügt.

Neil
quelle
3

TI-Basic, 53 16 Bytes

TI-Basic verwendet kein IEEE und die folgende Methode funktioniert für 0-9 (einschließlich) Dezimalstellen.

Prompt Str1,N
toString(round(expr(Str1),N

Vielen Dank an @JulianLachniet für den Nachweis, dass CE-Berechnungen den toString(Befehl haben, den ich nicht kannte (Color Edition-Berechnungen OS 5.2 oder höher sind erforderlich).

PS Ich hatte eine zweite Zeile mit, sub(Str1,1,N+inString(Str1,".aber dann wurde mir klar, dass es nutzlos war.

Timtech
quelle
Wie wird Nverwendet?
Matthias
@ Matthias Danke, dass du diesen Tippfehler entdeckt hast! Ich habe versehentlich die letzten drei Bytes mit meiner vorherigen Bearbeitung entfernt
Timtech
3

Java 7, 77 72 71 Bytes

<T>T c(T n,int d){return(T)"".format("%."+d+"f",new Double(n+""));}

-1 Byte dank @cliffroot

72-Byte-Antwort:

String c(String n,int d){return n.format("%."+d+"f",new Double(n));}

Im Gegensatz zu Python, rundet Java bereits richtig und gibt bereits einen String wenn Sie String.format("%.2f", aDouble)mit dem 2mit der Menge an Dezimalstellen ersetzt Sie wollen.

BEARBEITEN / HINWEIS: Ja, ich bin mir bewusst, dass new Float(n)1 Byte kürzer als ist new Double(n), aber anscheinend schlägt es für die Testfälle mit fehl 123456789.987654321. Siehe diesen Testcode bezüglich Double vs Float.

Erläuterung:

<T> T c(T n, int d){               // Method with generic-T & integer parameters and generic-T return-type (generic-T will be String in this case)
  return (T)"".format("%."+d+"f",  //  Return the correctly rounded output as String
    new Double(n+""));             //  After we've converted the input String to a decimal
}                                  // End of method

Testcode:

Probieren Sie es hier aus.

class M{
  static <T>T c(T n,int d){return(T)"".format("%."+d+"f",new Double(n+""));}

  public static void main(String[] a){
    System.out.println(c("14.225", 2));
    System.out.println(c("123.4", 5));
    System.out.println(c("99.9", 0));
    System.out.println(c("-99.9", 0));
    System.out.println(c("1", 0));
    System.out.println(c("1.", 0));
    System.out.println(c("1.0", 0));
    for(int i = 0; i < 8; i++){
      System.out.println(c("123456789.987654321", i));
    }
  }
}

Ausgabe:

14.23
123.40000
100
-100
1
1
1
123456790
123456790.0
123456789.99
123456789.988
123456789.9877
123456789.98765
123456789.987654
123456789.9876543
Kevin Cruijssen
quelle
1
Ein Byte kürzer:<T>T c(T n,int d){return(T)"".format("%."+d+"f",new Double(n+""));}
Cliffroot
2
Diese Lösung funktioniert nicht . Obwohl es sich bei dem Beispiel möglicherweise um ein rundes Problem mit halber Gerade / Auswärts-0 handelt, treten Gleitkommafehler auf, und OP hat seitdem klargestellt, dass willkürliche Genauigkeit unterstützt werden sollte.
CAD97
1
In der Tat scheitern Sie an den Beispielfällen in der Frage, die Sie hier reproduziert haben: 123456789.987654321, 4sollte 123456789.9877nicht sein123456789.9876
CAD97
2

Python (2/3), 394 Bytes

def rnd(s,p):
    m=s[0]=='-'and'-'or''
    if m:s=s[1:]
    d=s.find('.')
    l=len(s)
    if d<0:
        if p>0:d=l;l+=1;s+='.'
        else:return m+s
    e=(d+p+1)-l
    if e>0:return m+s+'0'*e
    o=''
    c=0
    for i in range(l-1,-1,-1):
        x=s[i]
        if i<=d+p:
            if i!=d:
                n=int(x)+c
                if n>9:n=0;c=1 
                else:c=0
                o+=str(n)
            else:
                if p>0:o+=x
        if i==d+p+1:c=int(x)>4
    if c:o+='1'
    return m+''.join(reversed(o))

Funktioniert für Zahlen mit beliebiger Genauigkeit.

Amol
quelle
5
Hey, und willkommen bei PPCG! Dies ist jedoch nicht Golf gespielt. Es gibt viele Leerzeichen, die Sie entfernen können. Die Antworten auf dieser Website müssen leider golfen.
Rɪᴋᴇʀ
Nur einige Dinge (es gibt wahrscheinlich noch viel mehr) ... Der Funktionsname kann ein Byte sein. Die erste Zeile kann s[0]<'0'die Zeichenfolgenmultiplikation verwenden und auch verwenden m='-'*(s[0]<'0'). Zeilen ohne Blockanweisungsbereiche können mit ;(z o='';c=0. B. ) zusammengefügt werden. Einige ifAnweisungen könnten wahrscheinlich durch Listenindizierung ersetzt werden, um den Bedarf an Zeilenumbrüchen und Tabulatoren weiter zu verringern. Die letzte Zeile könnte o[::-1]stattdessen ein Slice verwenden, reversed(o)und das ''.joinist redundant. Möglicherweise können Sie es auch neu schreiben, um die Notwendigkeit mehrerer returnAnweisungen zu vermeiden .
Jonathan Allan
2
... wenn Sie interessiert sind, finden Sie hier Tipps zum Golfen in Python .
Jonathan Allan
2

JavaScript (ES6), 155 Byte

(s,n)=>s.replace(/(-?\d+).?(.*)/,(m,i,d)=>i+'.'+(d+'0'.repeat(++n)).slice(0,n)).replace(/([0-8]?)([.9]*?)\.?(.)$/,(m,n,c,r)=>r>4?-~n+c.replace(/9/g,0):n+c)

Erläuterung: Die Zeichenfolge wird zuerst so normalisiert, dass sie eine .und eine n+1Dezimalstelle enthält. Die nachfolgende Ziffer, alle vorhergehenden 9s oder .s und jede vorhergehende Ziffer werden dann berücksichtigt. Wenn die letzte Ziffer kleiner als 5 ist, werden sie und alle unmittelbar vorhergehenden .einfach entfernt. Wenn sie jedoch größer als 5 ist, werden die 9s in 0s geändert und die vorherige Ziffer erhöht (oder 1 vorangestellt, wenn keine vorherige Ziffer vorhanden war).

Neil
quelle
1

Scala, 44 Bytes

(s:String,p:Int)=>s"%.${p}f"format s.toFloat

Prüfung:

scala> var x = (s:String,p:Int)=>s"%.${p}f"format s.toFloat
x: (String, Int) => String = <function2>

scala> x("14.225",2)
res13: String = 14.23
2xsaiko
quelle
1

Wunder , 10 Bytes

@@fix#1E#0

Verwendungszweck:

@@fix#1E#0

Stellen Sie die Dezimalgenauigkeit ein und fügen Sie bei Bedarf nachgestellte Nullen hinzu.

Mama Fun Roll
quelle
Gibt es eine TIO für diese?
Matthias
Nein, gibt es nicht, aber die Installation ist ziemlich einfach. Stellen Sie sicher, dass Sie Node.js (v6 +) und haben npm i -g wonderlang. Verwenden Sie den wonderBefehl, um die REPL zu starten, und fügen Sie den Code ein.
Mama Fun Roll
1

J, 22 17 Bytes

((10 j.[)]@:":".)

NB.    2    ((10 j.[)]@:":".)   '12.45678'
NB.    12.46 

Vielen Dank an @Conor O'Brien für die Korrektur meines Verständnisses der Regeln.

t=:4 :'(10 j.x)":".y'

    NB.    Examples
    NB.    4 t'12.45678'
    NB.    12.4568
    NB.    4 t'12.456780'
    NB.    12.4568
    NB.    4 t'12.4567801'
    NB.    12.4568
    NB.    2 t'12.45678'
    NB.      12.46
    NB.    2 t'12.4567801'
    NB.      12.46
    NB.    2 (10 j.[)":". '_12.4567801'
    NB.     _12.46

format    
    x t y
where x is a digit number of decimal places required and y
is the character string containing the value to be rounded.
Richard Donovan
quelle
Die Herausforderung erfordert, dass Sie die Anzahl der Stellen nach dem Dezimalpunkt auf N Dezimalstellen runden, nicht auf N Genauigkeitspunkte. Als solches 2 t '1234.456'sollte 1234.46statt6 t '1234.456'
Conor O'Brien