Angka bulat ke bilangan bulat terdekat

230

Saya sudah mencoba untuk mengumpulkan angka float panjang seperti:

32.268907563;
32.268907563;
31.2396694215;
33.6206896552;
...

Tanpa keberhasilan sejauh ini. Saya mencoba math.ceil(x), math.floor(x)(walaupun itu akan naik atau turun, yang bukan apa yang saya cari) dan round(x)yang tidak berhasil (angka masih mengambang).

Apa yang dapat saya lakukan?

EDIT: KODE:

for i in widthRange:
    for j in heightRange:
        r, g, b = rgb_im.getpixel((i, j))
        h, s, v = colorsys.rgb_to_hsv(r/255.0, g/255.0, b/255.0)
        h = h * 360
        int(round(h))
        print(h)
Vandernath
sumber
3
Saya akan mencobaint(x)
The Brofessor
apakah itu tidak akan memberikan kesalahan? literal tidak valid untuk int () dengan basis 10:
snh_nl

Jawaban:

366
int(round(x))

Akan membulatkannya dan mengubahnya menjadi bilangan bulat

EDIT:

Anda tidak memberikan int (putaran (h)) ke variabel apa pun. Saat Anda memanggil int (bulat (h)), ia mengembalikan nomor integer tetapi tidak melakukan hal lain; Anda harus mengubah baris itu untuk:

h = int(round(h))

Untuk menetapkan nilai baru ke h

EDIT 2:

Seperti @plowman katakan dalam komentar, Python round()tidak bekerja seperti yang biasanya diharapkan, dan itu karena cara nomor disimpan sebagai variabel biasanya bukan cara Anda melihatnya di layar. Ada banyak jawaban yang menjelaskan perilaku ini:

round () tampaknya tidak membulatkan dengan benar

Salah satu cara untuk menghindari masalah ini adalah dengan menggunakan Desimal seperti yang dinyatakan oleh jawaban ini: https://stackoverflow.com/a/15398691/4345659

Agar jawaban ini berfungsi dengan baik tanpa menggunakan pustaka tambahan, akan lebih mudah untuk menggunakan fungsi pembulatan khusus. Setelah banyak koreksi, saya datang dengan solusi berikut, yang sejauh ini saya uji menghindari semua masalah penyimpanan. Ini didasarkan pada penggunaan representasi string, yang diperoleh dengan repr()(TIDAK str()!). Kelihatannya berantakan tapi itu satu-satunya cara yang saya temukan untuk menyelesaikan semua kasus. Ia bekerja dengan kedua Python2 dan Python3.

def proper_round(num, dec=0):
    num = str(num)[:str(num).index('.')+dec+2]
    if num[-1]>='5':
        return float(num[:-2-(not dec)]+str(int(num[-2-(not dec)])+1))
    return float(num[:-1])

Tes:

>>> print(proper_round(1.0005,3))
1.001
>>> print(proper_round(2.0005,3))
2.001
>>> print(proper_round(3.0005,3))
3.001
>>> print(proper_round(4.0005,3))
4.001
>>> print(proper_round(5.0005,3))
5.001
>>> print(proper_round(1.005,2))
1.01
>>> print(proper_round(2.005,2))
2.01
>>> print(proper_round(3.005,2))
3.01
>>> print(proper_round(4.005,2))
4.01
>>> print(proper_round(5.005,2))
5.01
>>> print(proper_round(1.05,1))
1.1
>>> print(proper_round(2.05,1))
2.1
>>> print(proper_round(3.05,1))
3.1
>>> print(proper_round(4.05,1))
4.1
>>> print(proper_round(5.05,1))
5.1
>>> print(proper_round(1.5))
2.0
>>> print(proper_round(2.5))
3.0
>>> print(proper_round(3.5))
4.0
>>> print(proper_round(4.5))
5.0
>>> print(proper_round(5.5))
6.0
>>> 
>>> print(proper_round(1.000499999999,3))
1.0
>>> print(proper_round(2.000499999999,3))
2.0
>>> print(proper_round(3.000499999999,3))
3.0
>>> print(proper_round(4.000499999999,3))
4.0
>>> print(proper_round(5.000499999999,3))
5.0
>>> print(proper_round(1.00499999999,2))
1.0
>>> print(proper_round(2.00499999999,2))
2.0
>>> print(proper_round(3.00499999999,2))
3.0
>>> print(proper_round(4.00499999999,2))
4.0
>>> print(proper_round(5.00499999999,2))
5.0
>>> print(proper_round(1.0499999999,1))
1.0
>>> print(proper_round(2.0499999999,1))
2.0
>>> print(proper_round(3.0499999999,1))
3.0
>>> print(proper_round(4.0499999999,1))
4.0
>>> print(proper_round(5.0499999999,1))
5.0
>>> print(proper_round(1.499999999))
1.0
>>> print(proper_round(2.499999999))
2.0
>>> print(proper_round(3.499999999))
3.0
>>> print(proper_round(4.499999999))
4.0
>>> print(proper_round(5.499999999))
5.0

Akhirnya, jawaban yang diperbaiki adalah:

# Having proper_round defined as previously stated
h = int(proper_round(h))

EDIT 3:

Tes:

>>> proper_round(6.39764125, 2)
6.31 # should be 6.4
>>> proper_round(6.9764125, 1)
6.1  # should be 7

Gotcha di sini adalah bahwa decdesimal -th bisa menjadi 9 dan jika dec+1digit -th> = 5 maka 9 akan menjadi 0 dan 1 harus dibawa ke dec-1digit -th.

Jika kami mempertimbangkan hal ini, kami mendapatkan:

def proper_round(num, dec=0):
    num = str(num)[:str(num).index('.')+dec+2]
    if num[-1]>='5':
      a = num[:-2-(not dec)]       # integer part
      b = int(num[-2-(not dec)])+1 # decimal part
      return float(a)+b**(-dec+1) if a and b == 10 else float(a+str(b))
    return float(num[:-1])

Dalam situasi yang diuraikan di atas b = 10dan versi sebelumnya hanya akan menyatukan adan byang akan menghasilkan rangkaian di 10mana trailing 0 akan menghilang. Versi ini berubah bmenjadi tempat desimal yang tepat berdasarkan dec, sebagai carry yang tepat.

francisco sollima
sumber
2
print ("4.5)", int (round (4.5))) # memberi saya 4 print ("5.5)", int (round (5.5))) # # memberi saya 6
:,
Ini terkait dengan versi Python. Ini memberi saya 5 dan 6 menggunakan Python 2.7.9 dan, seperti yang Anda katakan, 4 dan 6 menggunakan Python 3.4.2
francisco sollima
1
Perlu dicatat: solusi ini tidak sesuai dengan cara yang mungkin Anda harapkan. Misalnya, int(round(4.5))membulatkan ke 4 sementara int(round(4.500001))dengan benar membulatkan ke 5.
bajak
Jika Anda ingin integer maka round(x)cukup dengan Python 3.6.2 (dan mungkin versi yang lebih rendah juga). Hasilnya sudah bertipe int. Catatan: round(x, n)akan dari tipe float.
Elmex80s
1
Ini tidak berfungsi untuk 112439.50093565206. Ini memberi o / p -> 11253.0. Sungguh aneh .. !!!!
ajin
24

Gunakan round(x, y). Ini akan mengumpulkan nomor Anda hingga tempat desimal yang Anda inginkan.

Sebagai contoh:

>>> round(32.268907563, 3)
32.269
Satyaki Sanyal
sumber
20

round(value,significantDigit)adalah solusi biasa, namun ini tidak beroperasi seperti yang diharapkan dari perspektif matematika ketika nilai bulat berakhir 5. Jika 5ada di digit tepat setelah angka yang dibulatkan, nilai-nilai ini kadang-kadang hanya dibulatkan seperti yang diharapkan (yaitu 8.005membulatkan menjadi dua digit desimal 8.01). Untuk nilai tertentu karena keanehan matematika floating point, mereka dibulatkan ke bawah!

yaitu

>>> round(1.0005,3)
1.0
>>> round(2.0005,3)
2.001
>>> round(3.0005,3)
3.001
>>> round(4.0005,3)
4.0
>>> round(1.005,2)
1.0
>>> round(5.005,2)
5.0
>>> round(6.005,2)
6.0
>>> round(7.005,2)
7.0
>>> round(3.005,2)
3.0
>>> round(8.005,2)
8.01

Aneh.

Dengan asumsi tujuan Anda adalah melakukan pembulatan statistik tradisional dalam sains, ini adalah pembungkus yang berguna untuk membuat roundfungsi berfungsi seperti yang diharapkan membutuhkan importhal-hal tambahan seperti Decimal.

>>> round(0.075,2)

0.07

>>> round(0.075+10**(-2*5),2)

0.08

Aha! Jadi berdasarkan ini kita dapat membuat fungsi ...

def roundTraditional(val,digits):
   return round(val+10**(-len(str(val))-1), digits)

Pada dasarnya ini menambahkan nilai yang dijamin lebih kecil dari digit string yang paling sedikit Anda coba gunakan round. Dengan menambahkan jumlah kecil itu mempertahankan roundperilaku dalam banyak kasus, sementara sekarang memastikan jika angka lebih rendah daripada yang dibulatkan adalah 5itu dibulatkan ke atas, dan jika 4itu dibulatkan ke bawah.

Pendekatan penggunaan 10**(-len(val)-1)itu disengaja, karena jumlah kecil terbesar yang dapat Anda tambahkan untuk memaksa perubahan, sambil juga memastikan bahwa nilai yang Anda tambahkan tidak pernah mengubah pembulatan bahkan jika desimal .hilang. Saya bisa menggunakan hanya 10**(-len(val))dengan persyaratan if (val>1)untuk mengurangi 1lebih banyak ... tapi lebih mudah untuk selalu mengurangi 1karena tidak akan banyak mengubah rentang angka desimal yang dapat diatasi dengan solusi ini. Pendekatan ini akan gagal jika nilai Anda mencapai batas tipe, ini akan gagal, tetapi untuk hampir seluruh rentang nilai desimal yang valid, itu harus bekerja.

Anda juga dapat menggunakan pustaka desimal untuk mencapai hal ini, tetapi pembungkus yang saya usulkan lebih sederhana dan mungkin lebih disukai dalam beberapa kasus.


Sunting: Terima kasih Blckknght untuk menunjukkan bahwa 5kasus pinggiran hanya terjadi untuk nilai-nilai tertentu. Juga versi sebelumnya dari jawaban ini tidak cukup eksplisit sehingga perilaku pembulatan ganjil hanya terjadi ketika digit langsung kalah dengan digit yang Anda bulatkan memiliki5 .

Jason R. Mick
sumber
Saya tidak yakin mengapa Anda berpikir desimal 5karena digit terakhirnya akan selalu bulat. Itu tidak terjadi di tes cepat saya hanya lakukan dengan nomor seperti 1.5, 2.5, 3.5dan seterusnya dan 1.05, 1.15, 1.25, 1.35pembulatan ke satu tempat desimal. Set pertama (tepat membagi dua pembulatan ke bilangan bulat kecil) selalu membulatkan ke bilangan bulat genap. Set terakhir tidak bulat secara konsisten, mungkin karena representasi biner yang tidak tepat dari beberapa nilai. Apung yang memiliki representasi biner yang tepat seperti 1.25bulat memiliki angka yang bahkan paling signifikan, tetapi yang lain tampak bulat secara acak.
Blckknght
Menarik ... kamu benar. round(4.0005,3)memberi 4.0dan round(1.0005,3)memberi 1.0, tetapi round(2.0005,3)memberi 2.001dan round(3.0005,3)memberi 3.001. Tapi itulah tepatnya mengapa solusi yang saya usulkan diperlukan ... Anda tidak tahu apa yang diharapkan dari putaran stok, dalam kasus penting ini!
Jason R. Mick
Terima kasih untuk ini. Fungsi Anda akan sangat berguna ketika masalah ini muncul.
TMWP
1
Apakah Anda bermaksud memiliki , digitspada akhir pernyataan pengembalian itu? Tidak ada pelesetan yang dimaksudkan. ( Maksudku, maksudku)
user3342816
Ah benar, memang itu seharusnya ada di sana. Tangkapan bagus ... terkejut tidak ada orang lain yang memperhatikan! Akan menyelamatkan mereka yang menggunakan solusi frustrasi. :-)
Jason R. Mick
15

Untuk yang positif, cobalah

int(x + 0.5)

Untuk membuatnya bekerja untuk yang negatif juga, cobalah

int(x + (0.5 if x > 0 else -0.5))

int()berfungsi seperti fungsi lantai dan karenanya Anda dapat memanfaatkan properti ini. Ini jelas cara tercepat.

Membingungkan
sumber
4
tidak bekerja untuk yang negatif>>> x=-0.999 >>> int(x), round(x), int(x+0.5) (0, -1.0, 0)
user2907934
3
Jika Anda peduli dengan kasus sudut jangan gunakan teknik "tambah 0,5 dan lantai" - ada beberapa nilai yang mungkin tidak sesuai dengan harapan Anda! Lihat stackoverflow.com/a/47302585/2732969 untuk pengambilan C ++ dan jawaban stackoverflow.com/a/38744026/2732969 dalam pertanyaan ini.
Anon
Saya membutuhkan metode cepat, tidak harus akurat dan tidak akan memiliki banyak kasus sudut, dan kesalahan dalam kasus sudut tidak penting dalam skenario saya. Jadi ini sudah pasti saya pergi ke untuk beberapa kasus khusus di mana kecepatan adalah prioritas. Jangan rekomendasikan untuk ketepatan atau ketepatan.
AgentM
11

Bukankah hanya Python melakukan setengah hingga genap , seperti yang ditentukan oleh IEEE 754 ?

Hati-hati mendefinisikan ulang, atau menggunakan pembulatan "non-standar" ...

(Lihat juga https://stackoverflow.com/a/33019948/109839 )

Mapio
sumber
2
Jawaban ini agak tidak jelas. Round half to evensama sekali tidak ditentukan oleh IEEE 754, tetapi hanya salah satu dari beberapa opsi pembulatan yang dijelaskan oleh standar . Round to nearest, ties away from zero(yaitu perilaku yang kebanyakan orang harapkan) juga merupakan opsi, dan merupakan default di, misalnya, C / C ++.
telepon
Saya setuju, kata-katanya cukup membingungkan. Apa yang saya maksudkan bahwa Python adalah membulatkan setengah ke tinggi (lihat tabel di akhir docs.python.org/3.7/library/... di mana rounddijelaskan) dan itu melakukannya sesuai dengan cara "round half to even" yang ditentukan untuk bekerja (atau dijelaskan) oleh standar.
Mapio
8

Anda juga dapat menggunakan asumsi numpy jika Anda menggunakan python3.x di sini adalah contohnya

import numpy as np
x = 2.3
print(np.rint(x))
>>> 2.0
sushmit
sumber
7

Solusi Anda dipanggil putaran tanpa menentukan argumen kedua (jumlah tempat desimal)

>>> round(0.44)
0
>>> round(0.64)
1

yang merupakan hasil yang jauh lebih baik daripada

>>> int(round(0.44, 2))
0
>>> int(round(0.64, 2))
0

Dari dokumentasi Python di https://docs.python.org/3/library/functions.html#round

round (angka [, ndigits])

Kembalikan angka yang dibulatkan ke presisi angka setelah titik desimal. Jika ndigits dihilangkan atau Tidak, ini mengembalikan integer terdekat ke inputnya.

Catatan

Perilaku round () untuk float bisa mengejutkan: misalnya, round (2.675, 2) memberi 2.67 bukannya 2.68 yang diharapkan. Ini bukan bug: ini adalah hasil dari fakta bahwa sebagian besar pecahan desimal tidak dapat diwakili persis seperti pelampung. Lihat Aritmatika Titik Apung: Masalah dan Batasan untuk informasi lebih lanjut.

Jay
sumber
1

Jika Anda memerlukan (misalnya) perkiraan dua digit untuk A, maka int(A*100+0.5)/100.0akan melakukan apa yang Anda cari.

Jika Anda membutuhkan perkiraan tiga digit, kalikan dan bagi dengan 1.000 dan seterusnya.

Hoo
sumber
1

Beberapa hal seperti ini juga harus bekerja

import numpy as np    

def proper_round(a):
    '''
    given any real number 'a' returns an integer closest to 'a'
    '''
    a_ceil = np.ceil(a)
    a_floor = np.floor(a)
    if np.abs(a_ceil - a) < np.abs(a_floor - a):
        return int(a_ceil)
    else:
        return int(a_floor)
Aabhaas
sumber
0

Untuk tujuan ini saya sarankan lakukan saja hal berikut -

int(round(x))

Ini akan memberi Anda bilangan bulat terdekat.

Semoga ini membantu!!

rahul ranjan
sumber
0

Saya menggunakan dan dapat menyarankan solusi berikut (python3.6):

y = int(x + (x % (1 if x >= 0 else -1)))

Ini berfungsi dengan baik untuk setengah angka (positif dan negatif) dan bekerja lebih cepat daripada int (putaran (x)):

round_methods = [lambda x: int(round(x)), 
                 lambda x: int(x + (x % (1 if x >= 0 else -1))),
                 lambda x: np.rint(x).astype(int),
                 lambda x: int(proper_round(x))]

for rm in round_methods:
    %timeit rm(112.5)
Out:
201 ns ± 3.96 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
159 ns ± 0.646 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
925 ns ± 7.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
1.18 µs ± 8.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

for rm in round_methods:
    print(rm(112.4), rm(112.5), rm(112.6))
    print(rm(-12.4), rm(-12.5), rm(-12.6))
    print('=' * 11)

Out:
112 112 113
-12 -12 -13
===========
112 113 113
-12 -13 -13
===========
112 112 113
-12 -12 -13
===========
112 113 113
-12 -13 -13
===========
Василий Прядченко
sumber