Zaokrąglij sznurek


10

Niektórych liczb dziesiętnych nie można dokładnie przedstawić jako liczb binarnych ze względu na wewnętrzną reprezentację liczb binarnych. Na przykład: zaokrąglenie 14,225 do dwóch cyfr dziesiętnych nie daje 14,23, jak można się spodziewać, ale 14,22.

Python :

In: round(14.225, 2)
Out: 14.22

Załóżmy jednak, że mamy ciąg znaków reprezentujący 14,225 jako „14,225”, powinniśmy być w stanie osiągnąć pożądane zaokrąglenie „14,23” jako ciąg znaków.

To podejście można uogólnić z dowolną precyzją.

Możliwe rozwiązanie Python 2/3

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

Wypróbuj online!

Zastosowanie :

     # 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

Zadanie

Argument wejściowy 1 : ciąg zawierający

  • co najmniej jedna cyfra ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  • co najwyżej jedna kropka dziesiętna ( .), która musi być poprzedzona co najmniej jedną cyfrą,
  • opcjonalny minus ( -) jako pierwszy znak.

Argument wejściowy 2 : nieujemna liczba całkowita

Wyjście : poprawnie zaokrąglony ciąg (podstawa 10)

zaokrąglenie = zaokrąglić w połowie od zera

To jest . Najmniejsza liczba bajtów wygrywa!


@KevinCruijssen 1) Nie musisz trzymać się ciągów znaków w treści swojej implementacji i możesz używać wbudowanego zaokrąglania. Niestety (w przypadku pytania) standard IEEE 754 jest powszechnie stosowanym standardem, a zatem wbudowane zaokrąglanie nie spowoduje pożądanego zachowania. 2) Ok, nie wiedziałem o piaskownicy.
Matthias

TI-Basic: round(A,B5 bajtów
Julian Lachniet

1
Jeśli chodzi o drugi argument wejściowy: 0nie jest dodatnią liczbą całkowitą, jest „nieujemny”.
Stewie Griffin,

1
Zakładam, że w razie potrzeby dodamy końcowe zera? Czy mógłbyś dodać przypadek testowy 123.4 & 5 --> 123.40000? Czy możemy założyć, że drugie wejście nigdy nie będzie większe niż liczba miejsc po przecinku po punkcie na pierwszym wejściu?
Kevin Cruijssen

1
@Matthias O ile nie możesz zintegrować Pythona z JavaScriptem (nigdy nie programowałem Pythona i tylko JS, więc szczerze mówiąc nie wiem, czy to możliwe) nie. Ale zawsze możesz dodać link Wypróbuj online ze swoim kodem testowym. EDYCJA: Zazwyczaj lepiej jest poczekać przynajmniej kilka dni, aż zaakceptujesz odpowiedź.
Kevin Cruijssen

Odpowiedzi:



5

Perl, 22 20 bajtów

printf"%.*f",pop,pop

Za pomocą:

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

Jest to wersja kodu Dady. Poprzedni:

printf"%*2\$.*f",@ARGV

2
printf"%.*f",pop,poppowinien działać
Dada,

5

PHP, 33 31 bajtów

PHP też zaokrągla poprawnie (przynajmniej w wersji 64-bitowej):

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

pobiera dane wejściowe z argumentów wiersza poleceń. Uruchom z -r.

PHP, brak wbudowanych, 133 bajtów

[,$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;

Uruchom go -nrlub przetestuj online .

awaria

[,$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;

Bajt zerowy nie działa; więc muszę użyć substr.


1
Możesz pisać "%.$argv[2]f"zamiast "%.{$argv[2]}f", oszczędzając 2 bajty.
Ismael Miguel

4

Ruby 2.3, 12 + 45 = 57

Korzysta z BigDecimalwbudowanego, ale musi być wymagany przed użyciem, co jest tańsze jako flaga.

Flaga: -rbigdecimal

funkcja:

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

Domyślnie używa Ruby 2.3 ROUND_HALF_UP


4

JavaScript (ES6), 44 bajty

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

Wypróbuj online:

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


4

Python, 114 105 103 96 91 89 bajtów

Zaoszczędź 5 bajtów dzięki Kevinowi Cruijssenowi
Zaoszczędź 2 bajty dzięki Krazorowi

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

Wypróbuj online!


1
from decimal import *a usunięcie tych trzech d.jest o 4 bajty krótsze.
Kevin Cruijssen

@KevinCruijssen: Dzięki!
Emigna,

2
Mógłbyś także zrobić, d=Decimala d() co uratowałoby kolejne 5. (Może być źle, bardzo sennie)
FMaz

@Krazor: O ile nie zrobiłem tego źle, zaoszczędziłem 2 bajty. Dzięki!
Emigna

Ups, o to mi chodziło. I tak zostawię moje senne myśli.
FMaz


3

BASH, 26 23 21 bajtów

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

stosowanie

zapisz w round_string.sh, chmod + x round_string.sh

./round_string.sh 23456789.987654321 3

edycja: nie trzeba ładować biblioteki


Objaśnienie: bc używa arbitralnej prekrecji, utwórz tutaj dokument z „<<<” zawierającym wartość skali jako drugiego parametru i pierwszego parametru podzielonego przez 1, aby wymusić interpretację skali.
marcosm

2
Daje 14.22to dane wejściowe 14.225 2, a nie14.23
Digital Trauma

3

AHK, 25 bajtów

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

Znowu jestem przytłoczony niemożnością użycia przez AHK parametrów przekazanych bezpośrednio w funkcjach, które akceptują nazwę zmiennej lub liczbę. Jeśli mogę wymienić az 1w Roundfunkcji, używa wartości 1. Gdy próbuję %1%, próbuje użyć pierwszego argumentu za treść jako nazwy zmiennej, która nie działa. Konieczność ustawienia go jako innej zmiennej najpierw kosztowała mnie 6 bajtów.


3

Partia, 390 bajtów

@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%%

Wyjaśnienie. Zaczyna od wyodrębnienia znaku, jeśli dotyczy. Następnie dzieli liczbę na liczby całkowite i ułamkowe. Ułamek jest wypełniany n+1zerami, aby mieć więcej niż ncyfry. nP (zero indeksowane) cyfrowy dzieli się przez 5, a to początkowa przenoszenia. nCyfry całkowite i ułamkowe są łączone, a przeniesienie dodawane znak po znaku. (Dodatkowe zera chronią przed falowaniem przenoszenia). Po zatrzymaniu falowania przenoszenia liczba jest rekonstruowana i wstawiany jest przecinek dziesiętny.


3

TI-Basic, 53 16 bajtów

TI-Basic nie używa IEEE, a poniższa metoda działa dla 0-9 (włącznie) pozycji dziesiętnych.

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

Dzięki @JulianLachniet za wykazanie, że cielęta CE mają toString( polecenie, którego nie znałem (wymagana jest edycja Calcs OS 5.2 lub nowsza).

PS Miałem drugą linię, sub(Str1,1,N+inString(Str1,".ale potem zdałem sobie sprawę, że to było bezużyteczne.


Jak Nstosować?
Matthias

@Matthias Dzięki za złapanie tej literówki! Przypadkowo usunąłem ostatnie trzy bajty z moją poprzednią edycją
Timtech

3

Java 7, 77 72 71 bajtów

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

-1 bajt dzięki @cliffroot

72-bajtowa odpowiedź:

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

W przeciwieństwie do Pythona, Java już zaokrągla poprawnie i już zwraca ciąg, gdy używasz String.format("%.2f", aDouble)z2 zastąpioną liczbą miejsc po przecinku, którą chcesz.

EDYCJA / UWAGA: Tak, wiem, że new Float(n)jest o 1 bajt krótszy niż new Double(n), ale najwyraźniej nie udaje się to z przypadkami testowymi 123456789.987654321. Zobacz ten kod testowy dotyczący Double vs Float.

Wyjaśnienie:

<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

Kod testowy:

Wypróbuj tutaj.

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

Wynik:

14.23
123.40000
100
-100
1
1
1
123456790
123456790.0
123456789.99
123456789.988
123456789.9877
123456789.98765
123456789.987654
123456789.9876543

1
Jeden bajt krótszy:<T>T c(T n,int d){return(T)"".format("%."+d+"f",new Double(n+""));}
cliffroot

2
To rozwiązanie nie działa . Chociaż przykład ten może potencjalnie dotyczyć okrągłej połowy parzystej / braku 0, występują błędy zmiennoprzecinkowe, a OP wyjaśnił, że należy wspierać arbitralną precyzję.
97 CAD

1
W rzeczywistości zawiodłeś przykładowe przypadki w pytaniu, które tutaj odtworzyłeś: 123456789.987654321, 4powinno być 123456789.9877, nie123456789.9876
CAD97

2

Python (2/3), 394 bajty

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

Działa dla dowolnych liczb dokładności.


5
Cześć, witamy w PPCG! Nie jest to jednak gra w golfa. Istnieje wiele białych znaków, które można usunąć. Niestety, odpowiedzi na tej stronie wymagają gry w golfa.
Rɪᴋᴇʀ

Tylko kilka rzeczy (prawdopodobnie jest ich znacznie więcej) ... Nazwa funkcji może być jednobajtowa. Pierwsza linia może używać s[0]<'0'i może również wykorzystywać ciąg mnożenia m='-'*(s[0]<'0'). Linie bez przedziałów instrukcji blokowych można łączyć z ;(np o='';c=0.). Niektóre ifinstrukcje można prawdopodobnie zastąpić indeksowaniem list, aby jeszcze bardziej ograniczyć potrzebę podziału wiersza i tabulacji. W ostatnim wierszu można użyć plasterka o[::-1]zamiast reversed(o)i ''.joinjest nadmiarowy. Możesz również być w stanie przepisać go, aby uniknąć konieczności używania wielu returninstrukcji.
Jonathan Allan

2
... jeśli jesteś zainteresowany, znajdziesz tutaj wskazówki dotyczące gry w golfa w Pythonie .
Jonathan Allan

2

JavaScript (ES6), 155 bajtów

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

Objaśnienie: Łańcuch jest najpierw znormalizowane do przechowywania .i n+1dziesiętnych cyfr. Końcowa cyfra, wszelkie poprzedzające 9s lub .s oraz dowolna poprzedzająca cyfra są następnie brane pod uwagę. Jeśli ostatnia cyfra jest mniejsza niż 5, wówczas i wszystkie bezpośrednio poprzedzające .są po prostu usuwane, ale jeśli jest większa niż 5, 9s są zmieniane na 0s, a poprzednia cyfra jest zwiększana (lub 1 prefiks, jeśli nie było poprzedniej cyfry).



1

Scala, 44 bajty

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

Test:

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

1

Cud , 10 bajtów

@@fix#1E#0

Stosowanie:

@@fix#1E#0

Ustaw dokładność dziesiętną i w razie potrzeby dodaj końcowe zera.


Czy dla tego istnieje TIO?
Matthias

Nie, nie ma, ale instalacja jest dość łatwa. Upewnij się, że masz Node.js (wersja 6 +) i npm i -g wonderlang. Użyj wonderpolecenia, aby odpalić REPL i wkleić kod.
Mama Fun Roll

1

J, 22 17 bajtów

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

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

Dzięki @Conor O'Brien za poprawienie mojego zrozumienia zasad.

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.

Wyzwanie wymaga podania liczby cyfr po przecinku do zaokrąglenia do N miejsc po przecinku, a nie do N punktów dokładności. Jako taki 2 t '1234.456'powinien dać 1234.46zamiast6 t '1234.456'
Conor O'Brien
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.