Bulatkan talinya

10

Beberapa angka desimal tidak dapat secara tepat direpresentasikan sebagai pelampung biner karena representasi internal pelampung biner. Sebagai contoh: pembulatan 14.225 ke dua angka desimal tidak menghasilkan 14.23 seperti yang diharapkan, tetapi dalam 14.22.

Python :

In: round(14.225, 2)
Out: 14.22

Asumsikan, bagaimanapun, bahwa kita memiliki representasi string 14.225 sebagai '14 .225 ', kita harus dapat mencapai pembulatan yang kita inginkan '14 .23' sebagai representasi string.

Pendekatan ini dapat digeneralisasi ke presisi sewenang-wenang.

Kemungkinan Solusi 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

Cobalah online!

Penggunaan :

     # 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

Tugas

Argumen input 1 : string yang berisi

  • setidaknya satu digit ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
  • paling banyak satu titik desimal ( .) yang harus didahului oleh setidaknya satu digit,
  • minus opsional ( -) sebagai karakter pertama.

Argumen masukan 2 : bilangan bulat non-negatif

Output : string yang dibulatkan dengan benar (basis 10)

pembulatan = Membulatkan setengah dari nol

Ini adalah . Jumlah byte terendah menang!

Matthias
sumber
@KevinCruijssen 1) Anda tidak perlu tetap menggunakan string di tubuh implementasi Anda dan diizinkan untuk menggunakan pembulatan bawaan. Sayangnya (untuk pertanyaan) standar IEEE 754 adalah standar yang banyak digunakan dan dengan demikian pembulatan bawaan tidak akan menghasilkan perilaku yang diinginkan. 2) Ok, tidak menyadari kotak pasir.
Matthias
TI-Dasar: round(A,B5 byte
Julian Lachniet
1
Mengenai argumen input kedua: 0bukan bilangan bulat positif, itu "non-negatif".
Stewie Griffin
1
Saya berasumsi kita menambahkan nol tambahan jika diperlukan? Bisakah Anda menambahkan test case 123.4 & 5 --> 123.40000? Atau dapatkah kita berasumsi bahwa input kedua tidak akan pernah lebih besar dari jumlah desimal setelah titik pada input pertama?
Kevin Cruijssen
1
@ Matthias Kecuali Anda dapat mengintegrasikan Python dengan JavaScript (Saya tidak pernah memprogram Python, dan nyaris JS, jadi saya jujur ​​tidak tahu apakah itu mungkin) tidak. Tetapi Anda selalu dapat menambahkan tautan Coba online dengan kode tes Anda. EDIT: Juga, biasanya lebih baik menunggu setidaknya beberapa hari sampai Anda menerima jawaban.
Kevin Cruijssen

Jawaban:

2

APL (Dyalog) , 4 byte

Dyalog APL menggunakan presisi internal yang cukup.

⎕⍕⍎⍞

Cobalah online!

⍎⍞ jalankan input string

⎕⍕ dapatkan input numerik dan gunakan itu sebagai presisi untuk pemformatan

Adm
sumber
Mengapa ini 4 bukannya 8 byte?
Matthias
@Matthias Karena Dyalog APL memiliki SBCS
Adm
5

Perl, 22 20 byte

printf"%.*f",pop,pop

Menggunakan:

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

Ini adalah versi kode Dada. Sebelumnya:

printf"%*2\$.*f",@ARGV
Denis Ibaev
sumber
2
printf"%.*f",pop,popharus bekerja
Dada
5

PHP, 33 31 byte

Putaran PHP dengan benar juga (setidaknya pada 64 bit):

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

mengambil input dari argumen baris perintah. Jalankan dengan -r.

PHP, tanpa built-in, 133 byte

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

Jalankan dengan -nratau coba online .

kerusakan

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

Bita nol tidak berfungsi; jadi saya harus menggunakan substr.

Titus
sumber
1
Anda dapat menulis "%.$argv[2]f"alih-alih "%.{$argv[2]}f", menghemat 2 byte.
Ismael Miguel
4

Ruby 2.3, 12 + 45 = 57

Menggunakan BigDecimalbuilt-in, tetapi harus diperlukan sebelum digunakan, yang lebih murah untuk dilakukan sebagai flag.

bendera: -rbigdecimal

fungsi:

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

Ruby 2.3 secara default menggunakan ROUND_HALF_UP

SztupY
sumber
4

Javascript (ES6), 44 byte

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

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

powelles
sumber
4

Python, 114 105 103 96 91 89 byte

Disimpan 5 byte berkat Kevin Cruijssen
Disimpan 2 byte berkat Krazor

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

Cobalah online!

Emigna
sumber
1
from decimal import *dan menghapus ketiganya d.adalah 4 byte lebih pendek.
Kevin Cruijssen
@KevinCruijssen: Terima kasih!
Emigna
2
Anda juga dapat melakukannya d=Decimaldan d() , yang akan menyelamatkan 5. lainnya (Mungkin salah, sangat mengantuk)
FMaz
@ Krazor: Kecuali saya salah melakukannya saya menghemat 2 byte. Terima kasih!
Emigna
Woops, itu yang saya maksud. Akan meninggalkan pikiranku mengantuk.
FMaz
4

REXX, 24 byte

arg n p
say format(n,,p)

Karena REXX selalu menggunakan representasi teks angka, pembulatan angka yang benar adalah gratis.

Cobalah online!

idrougge
sumber
Wow. penyalahgunaan bahasa.
Matthew Roh
Apakah REXX memiliki kompiler online?
Kevin Cruijssen
Ini (terutama) bahasa yang ditafsirkan.
idrougge
3

BASH, 26 23 21 byte

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

pemakaian

simpan ke round_string.sh, chmod + x round_string.sh

./round_string.sh 23456789.987654321 3

sunting: tidak perlu memuat perpustakaan

marcosm
sumber
Penjelasan: bc menggunakan precission arbitrary, buat dokumen di sini dengan '<<<' yang berisi nilai skala sebagai parameter kedua dan parameter pertama dibagi 1 untuk memaksa penafsiran skala.
marcosm
2
Ini memberi 14.22input 14.225 2, dan bukan14.23
Digital Trauma
3

AHK, 25 byte

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

Sekali lagi saya digagalkan oleh ketidakmampuan AHK untuk menggunakan parameter yang diteruskan secara langsung dalam fungsi yang menerima baik nama variabel atau nomor. Jika saya ganti adengan 1dalam Roundfungsi, ia menggunakan nilai 1. Jika saya mencoba %1%, mencoba untuk menggunakan argumen pertama isi sebagai nama variabel, yang tidak bekerja. Setelah menetapkannya sebagai variabel lain, biayanya 6 byte.

Toast insinyur
sumber
3

Batch, 390 byte

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

Penjelasan. Mulai dengan mengekstraksi tanda, jika ada. Kemudian, bagi angka menjadi bilangan bulat dan pecahan. Fraksi ini diisi dengan n+1nol untuk memastikan memiliki lebih dari ndigit. The nth (zero-diindeks) digit dibagi oleh 5, dan ini adalah carry awal. Angka integer dan nfraksi digabungkan, dan carry ditambahkan karakter demi karakter. (Nol ekstra melindungi dari bawa riak.) Setelah carry berhenti, riak nomor direkonstruksi dan titik desimal apa pun dimasukkan.

Neil
sumber
3

TI-Basic, 53 16 byte

TI-Basic tidak menggunakan IEEE dan metode di bawah ini berfungsi untuk posisi desimal 0-9 (inklusif).

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

Terima kasih kepada @JulianLachniet karena menunjukkan bahwa CE calcs memiliki toString(perintah yang tidak saya ketahui (Color Edition calcs OS 5.2 atau lebih tinggi diperlukan).

PS Saya memang memiliki baris kedua dengan sub(Str1,1,N+inString(Str1,".tetapi kemudian saya menyadari itu tidak berguna.

Timtech
sumber
Bagaimana Ndigunakan?
Matthias
@Matthias Terima kasih telah menangkap kesalahan ketik itu! Saya tidak sengaja menghapus tiga byte terakhir dengan suntingan saya sebelumnya
Timtech
3

Java 7, 77 72 71 byte

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

-1 byte terima kasih kepada @cliffroot

Jawaban 72 byte:

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

Tidak seperti Python, Java sudah bulat dengan benar dan sudah mengembalikan String ketika Anda menggunakan String.format("%.2f", aDouble)dengan 2jumlah desimal yang Anda inginkan.

EDIT / CATATAN: Ya, saya sadar new Float(n)1 byte lebih pendek dari new Double(n), tetapi ternyata gagal untuk kasus uji dengan 123456789.987654321. Lihat kode tes ini tentang Double vs Float.

Penjelasan:

<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

Kode uji:

Coba di sini.

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

Keluaran:

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
sumber
1
Satu byte lebih pendek:<T>T c(T n,int d){return(T)"".format("%."+d+"f",new Double(n+""));}
cliffroot
2
Solusi ini tidak berfungsi . Meskipun contoh ini berpotensi sebagai masalah setengah-setengah / jauh-0, kesalahan floating point memang terjadi dan sejak itu OP telah mengklarifikasi bahwa presisi sewenang-wenang harus didukung.
CAD97
1
Bahkan, Anda gagal contoh kasus dalam pertanyaan yang Anda buat di sini: 123456789.987654321, 4seharusnya 123456789.9877, tidak123456789.9876
CAD97
2

Python (2/3), 394 byte

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

Berfungsi untuk angka presisi yang berubah-ubah.

Amol
sumber
5
Hai, dan selamat datang di PPCG! Namun, ini bukan golf. Ada banyak ruang kosong yang bisa Anda hapus. Jawaban di situs ini diperlukan untuk golf, maaf.
R
Hanya beberapa hal (kemungkinan ada lebih banyak) ... Nama fungsi dapat satu byte. Baris pertama bisa menggunakan s[0]<'0'dan juga bisa menggunakan string multiplikasi m='-'*(s[0]<'0'),. Baris tanpa bentang pernyataan blok dapat digabungkan bersama; (misalnya o='';c=0). Beberapa ifpernyataan mungkin dapat diganti dengan pengindeksan daftar untuk lebih mengurangi kebutuhan akan jeda baris dan tab. Baris terakhir bisa menggunakan irisan o[::-1],, bukan reversed(o)dan ''.joinitu berlebihan. Anda mungkin juga dapat menulis ulang untuk menghindari kebutuhan akan banyak returnpernyataan.
Jonathan Allan
2
... jika Anda tertarik ada tips untuk bermain golf di Python di sini .
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)

Penjelasan: String pertama kali dinormalisasi untuk mengandung digit a .dan n+1desimal. The digit trailing, setiap sebelumnya 9s atau .s, dan setiap digit sebelumnya, kemudian dipertimbangkan. Jika digit terakhir kurang dari 5 maka digit tersebut dan setiap yang sebelumnya segera .dihapus, tetapi jika lebih besar dari 5 maka 9s diubah menjadi 0s dan digit sebelumnya bertambah (atau 1 diawali jika tidak ada digit sebelumnya).

Neil
sumber
1

Scala, 44 byte

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

Uji:

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

Bertanya-tanya , 10 byte

@@fix#1E#0

Pemakaian:

@@fix#1E#0

Atur presisi desimal dan tambahkan nol tambahan jika perlu.

Mama Fun Roll
sumber
Apakah ada TIO untuk yang ini?
Matthias
Tidak ada, tetapi instalasi cukup mudah. Pastikan Anda memiliki Node.js (v6 +), dan npm i -g wonderlang. Gunakan wonderperintah untuk menjalankan REPL, dan tempel kode.
Mama Fun Roll
1

J, 22 17 byte

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

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

Terima kasih kepada @Conor O'Brien karena mengoreksi pemahaman saya tentang aturan.

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
sumber
Tantangannya mengharuskan Anda untuk mengambil jumlah digit setelah titik desimal untuk membulatkan ke desimal N, bukan N poin presisi. Dengan demikian, 2 t '1234.456'harus memberikan 1234.46bukannya6 t '1234.456'
Conor O'Brien