Rounding yang Memuaskan

16

Rounding yang Memuaskan

Anda tahu kapan Anda berada di kelas sains, dan diminta membulatkan ke 2 buah ara, tetapi jawaban Anda adalah 5.2501...? Anda harus membulatkan tekad 5.3, tapi itu sangat tidak memuaskan! Dengan membulatkan ke 5.3, Anda pergi dengan 0,05 keseluruhan, yang merupakan jumlah besar dibandingkan dengan 0,1 (nilai tempat Anda pembulatan ke)! Jadi tolong bantu saya dengan cara yang memuaskan.

Untuk membulatkan dengan cara yang memuaskan, Anda harus membulatkan angka pertama yang Anda temui yang menghasilkan kesalahan yang relatif kecil - kurang dari setengah kesalahan maksimum yang mungkin terjadi saat pembulatan. Pada dasarnya, Anda perlu membulatkan setiap kali Anda menemukan 0, 1, 8, atau 9. Jika itu tidak pernah terjadi, kembalikan input apa adanya. Jangan membulatkan angka nol di depan atau yang lainnya - yang memang tidak memuaskan.

Memasukkan

Nilai string atau float yang mewakili angka desimal non-negatif.

Keluaran

Angka desimal yang sama dibulatkan dengan memuaskan, dalam format string atau float.

Contohnya

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

Ini adalah tantangan , jadi kode terpendek menang!

Quintec
sumber
Sandbox
Quintec
Apakah string seperti 036.40000dianggap sebagai output yang valid?
Arnauld
1
Bisakah kita berasumsi bahwa a .0 bagian akan diberikan untuk bilangan bulat? Juga, 0tidak positif.
Erik the Outgolfer
@EriktheOutgolfer Tidak, Anda mungkin tidak - juga terima kasih, berubah menjadi tidak negatif.
Quintec
1
Jadi 19putaran untuk 20tetapi0.19 putaran ke 0? Mengapa?
Neil

Jawaban:

2

JavaScript (ES6),  100 99 98  78 byte

Mengambil input sebagai string. Mengembalikan float.

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

Cobalah online!

Bagaimana?

Kami pertama-tama menambahkan awal 0 ke string input, sehingga kami dijamin memiliki digit sebelum 8 kemungkinan memimpin8 atau 9 , yang harus memicu pembulatan segera.

Bendera j diatur ke 1 selama kita mencari digit di mana kita dapat melakukan pembulatan yang memuaskan, dan ditetapkan ke 0 setelahnya.

Karena 0 terdepan ditambahkan ke string yang sedang kita lalui tetapi s dibiarkan tidak berubah, d berisi karakter saat ini dan s[i] menunjuk kekarakterberikutnya.

Kami menggunakan kode berikut untuk memuat digit berikutnya n , melompati pemisah desimal yang mungkin:

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

Meskipun string yang berubah dalam JavaScript, ekspresi ++s[i]akan kembali s[i]+1 jika mengandung nilai numerik, meskipun s[i] tidak benar-benar bertambah. Oleh karena itu, ekspresi !++s[i]dievaluasi menjadi false (dipaksa ke 0 ) untuk semua digit (termasuk 0 ) dan untuk true (dipaksakan ke 1 ) untuk pemisah desimal ".".

d + --jn01d + j--n89j00d1

Arnauld
sumber
1
Dan bola pinball / karet jatuh ke selokan! :)
Quintec
2

Ruby , 79 77 69 67 65 byte

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

Cobalah online!

Penjelasan

  • ->n Ambil input sebagai string
  • z=n+".0"Buat string sementara zyang dijamin mengandung titik dan digit yang relevan.
  • i=z=~/\./Tentukan posisi titik desimal zdan tetapkan i.
  • z[i]='' Jatuhkan titik sehingga tidak menghalangi.
  • z=~/(?!^)[01]|8|9/Tentukan posisi non-start 0-1atau apa pun 8-9, mana yang lebih dulu.
  • (...)-i Perbedaan ini adalah jumlah tempat desimal yang akan disimpan, negatif jika kita akan membulatkan titik kiri.
  • n.to_f.round ... Konversikan ke float dan lakukan pembulatan.
Kirill L.
sumber
1

Jelly , 34 byte

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

Cobalah online!

-1 terima kasih kepada Jonathan Allan .

Erik the Outgolfer
sumber
Mengapa ŒV? Saya pikir Vakan bekerja juga.
Jonathan Allan
@JonathanAllan Tidak (pada dasarnya kebiasaan pembulatan bankir)
Erik the Outgolfer
Oh, karena tidak bekerja pada input? Coba _>¥0ɓVærseperti milik saya (saya melewatkan penggunaan diad cepat jadi terima kasih juga!)
Jonathan Allan
@ Jonathan Allan Ah, penggunaan rantai yang pintar, terima kasih.
Erik the Outgolfer
1

Jelly ,  30  29 byte

-1 terima kasih kepada Erik the Outgolfer (penggunaan diad cepat ¥dari jawabannya)

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

Tautan monadik yang menerima daftar karakter yang menghasilkan float.

Cobalah online! Atau lihat test-suite .

Bagaimana

Catatan pertama bahwa string input dibuat secara eksklusif dari karakter 0123456789.yang memiliki tata cara [48,49,50,51,52,53,54,55,56,57,46], yang memiliki sisa ketika dibagi dengan delapan karakter [0,1,2,3,4,5,6,7,0,1,6]. Satu-satunya karakter yang antara -1dan 1inklusif yang 0, 1, 8, dan 9.

Lebih jauh lagi jika kita mengurangi delapan dari ordinals ( [40,41,42,43,44,45,46,47,48,49,38]) yang sama (cukup jelas) berlaku. Jika kita membagi dua ini ([20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19] ) satu-satunya karakter yang memiliki sisa ketika dibagi delapan yang antara -1dan 1inklusif adalah 8dan 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)
Jonathan Allan
sumber
1

Retina 0.8.2 , 75 byte

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

Cobalah online! Tautan termasuk kasus uji. Penjelasan:

^[89]
10

Tangani kasus seorang pemimpin 8 atau 9.

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

Jika ada non-leading 0atau 1, maka nolkan dan sisa string keluar. Juga, jika ada8 atau 9, lalu tinggalkan, tetapi nol sisa string. (Tetapi biarkan titik desimal tidak berubah dalam kedua kasus.)

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

Jika masih ada 8 atau 9pada titik ini, maka nolkan, dan tambahkan digit sebelumnya (mungkin sebelum titik desimal).

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

Hapus trailing nol jika mereka setelah titik desimal, tetapi hanya hapus titik desimal jika tidak ada angka lain di antaranya.

Neil
sumber
1

C (gcc) , 111 102 byte

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

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

Cobalah online!

Bisa lebih pendek jika saya menggunakan ganda daripada desimal, tapi saya menggunakan desimal untuk menjaga akurasi, atau angka seperti 547.4726 akan menjadi 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();}

Cobalah online! (Versi kurang akurat)

Perwujudan Ketidaktahuan
sumber