2012-04-12 37 views
7

Tôi đang cố gắng để phân chia một số một số lượng lớn bằng Python nhưng tôi nhận được một số kết quả lạChia số lượng lớn bằng Python

NStr = "7D5E9B01D4DCF9A4B31D61E62F0B679C79695ACA70BACF184518" \ 
     "8BDF94B0B58FAF4A3E1C744C5F9BAB699ABD47BA842464EE93F4" \ 
     "9B151CC354B21D53DC0C7FADAC44E8F4BDF078F935D9D07A2C07" \ 
     "631D0DFB0B869713A9A83393CEC42D898516A28DDCDBEA13E87B" \ 
     "1F874BC8DC06AF03F219CE2EA4050FA996D30CE351257287" 

N = long(NStr, 16) 
f2 = 476 

fmin = N/float(f2) 

print N - (fmin * float(f2)) 

này kết quả đầu ra như 0.0 như mong đợi. Tuy nhiên nếu tôi, ví dụ, thay đổi mã để

fmin = N/float(f2) 
fmin += 1 

tôi vẫn nhận được một sản lượng 0.0

Tôi cũng đã cố gắng sử dụng các gói số thập phân

fmin = Decimal(N)/Decimal(f2) 
print Decimal(N) - (fmin * Decimal(f2)) 

Nhưng điều đó mang lại cho tôi một đầu ra của -1.481136900397802034028076389E+280

Tôi giả sử tôi không nói với python cách xử lý các số lớn đúng cách, nhưng tôi bị bối rối về nơi cần đi từ đây.

Tôi cũng nên thêm rằng mục tiêu cuối cùng là để tính toán

fmin = ceil(N/float(f2)) 

như một lâu dài và chính xác càng tốt

+0

Có phải 'f2' luôn là số nguyên không? – huon

+0

@dbaupp có nó sẽ là –

Trả lời

3

Mở rộng trên nhận xét của tôi, nếu Nf2long s Nghiêm lớn hơn 0, sau đó

fmin = (N - 1) // f2 + 1 

là chính xác ceil(N/float(f2)) (nhưng thậm chí chính xác hơn là sử dụng phao).

(Việc sử dụng // hơn / cho phép chia số nguyên là để tương thích với Python 3.x dành cho không có nỗ lực thêm.)

Đó là vì N // f2 mang đến cho bạn (về cơ bản) floor(N/float(f2)) và do đó N // f2 + 1 là hầu như luôn luôn giống như ceil. Tuy nhiên, khi N là bội số của f2, N // f2 + 1 quá lớn (+1 không nên ở đó) nhưng sử dụng N - 1 khắc phục sự cố này và không vi phạm trường hợp khác.

(Điều này không làm việc cho một trong hai N, f2 nhỏ hơn hoặc bằng 0, nhưng có thể xử lý riêng)

4

fmin là một float sau khi bạn chia số nguyên dài bởi một phao. Giá trị của nó là 1.84952718165824e+305. Thêm 1 vào đó không thay đổi chút nào, độ chính xác đơn giản là không cao.

Nếu bạn làm phép chia số nguyên thay vào đó, fmin vẫn là một long:

>>> fmin = N/f2 
>>> fmin 
18495271816582402193321106509793602189617847415669131056768139225220221855498293 
49983070478076000952025038039460539798061570960870927236986153971731443029057201 
52035339202255934728764897424408896865977423536890485615063959262845076766281553 
766072964756078264853041334880929452289298495368916583660903481130L 
>>> N - (fmin * f2) 
111L 

Tất nhiên, bạn không nhận được 0 vì sự phân chia số nguyên, nơi một phần thập phân của kết quả được loại bỏ. Nhưng bây giờ, thêm 1 sẽ tạo sự khác biệt:

>>> N - ((fmin+1) * f2) 
-365L 

Sử dụng các module Decimal không làm thay đổi vấn đề:

>>> from decimal import Decimal, getcontext 
>>> fmin = Decimal(N)/Decimal(f2) 
>>> fmin 
Decimal('1.849527181658240219332110651E+305') 

Vẫn là không chính xác giới hạn, và thậm chí nếu bạn thiết lập Decimal.getcontext().prec = 2000, bạn vẫn sẽ không nhận được chính xác 0.

+0

Đây không phải là hành vi tôi thấy trên python 2.7.2 – Marcin

+0

Đây là những gì tôi thấy trên Python 2.7.2 (Windows 7 x64, phiên bản 64 bit của Python). Bạn đang dùng gì? –

+0

Vì vậy, nếu tôi muốn làm 'fmin = math.ceil (N/f2)' và nhận được câu trả lời trở lại như là một độ dài nhưng với mức độ chính xác cao nhất có thể thì tôi sẽ làm gì? –

1

Nổi chỉ đơn giản là không có đủ độ chính xác cho loại hoạt động này.

Bạn có thể cải thiện độ chính xác của mô-đun decimal với getcontext(). Ví dụ sử dụng 65.536 chữ số thập phân:

from decimal import Decimal, getcontext 
getcontext().prec = 2**16 

Sau đó:

>>> print Decimal(N) - (fmin * Decimal(f2)) 
-2E-65228 

Vẫn không 0 nhưng gần gũi hơn :)

Xem this answer để làm một ceil() trên một đối tượng Decimal.

1

Tôi cũng tìm thấy giống như hành vi trong python 2.7.2:

In [17]: N 
Out[17]: 8803749384693223444020846698661754642258095369858506383021634271204825603217187705919415475641764531639181067832169438773077773745613648054092905441668 
8183122792368821460273824930892091174018634908205253603559871152770444609114256540750019592650731223893254070047675403322419289706083795604293822590057017991L 

In [18]: 

In [18]: (fmin * float(f2)) 
Out[18]: 8.803749384693223e+307 
In [19]: N - (fmin * float(f2)) 
Out[19]: 0.0 

In [20]: (fmin * float(f2)) 
Out[20]: 8.803749384693223e+307 

In [21]: N == (fmin * float(f2)) 
Out[21]: False 

In [22]: N < (fmin * float(f2)) 
Out[22]: False 

In [23]: N > (fmin * float(f2)) 
Out[23]: True 

Vì lý do tôi không hiểu, có vẻ như rằng trừ một phao từ một sản lượng dài 0.

Các giải pháp sẽ xuất hiện để được chuyển đổi cả một decimal.Decimal:

In [32]: decimal.Decimal(N) - decimal.Decimal(fmin * float(f2)) 
Out[32]: Decimal('4.099850360284731589507226352E+291') 
+0

Nhưng nếu bạn chuyển đổi cả hai thành số thập phân bạn sẽ nhận được câu trả lời sai, chắc chắn nó phải là '0.0' –

+0

@NathanBaggs Tại sao nó phải là 0? Chúng không bằng nhau. – Marcin

+0

nếu 'fmin = N/f2' thì' fmin * f2 = N' –

1

Fraction từ các module fractions có thể có ích:

> : N = Fraction(N) 
> : f2 = Fraction(f2) 
> : fmin = N/f2 
> : print N-f2*fmin 
0 
> : fmin += 1 
> : print N-f2*fmin 
-476 

Nhưng nếu mục tiêu duy nhất của bạn là để tính toán ceil(N/float(f2)) bạn có thể sử dụng:

> : fmin = N/f2 + int(ceil((N % f2)/float(f2))) 
> : print fmin 
184952718165824021933211065097936021896178474156691310567681392252202218554982934998307047807600095202503803946053979806157096087092723698615397173144302905720152035339202255934728764897424408896865977423536890485615063959262845076766281553766072964756078264853041334880929452289298495368916583660903481131 
+0

Math.ceil (N/float (f2)) có cho kết quả tương tự không, nếu không phải vì sao? –

+0

@NathanBaggs: Không, không. Như những người khác đã chỉ ra, khi bạn chuyển sang nổi bạn đang mất thông tin. Đó là trước cuộc gọi 'ceil'. Trong mọi trường hợp, 'ceil' sẽ trả về một phao, vậy nên lại có một lần nữa. Cùng một vấn đề. – Avaris

+0

'int (ceil ((N% f2)/float (f2)))' quá phức tạp cho công việc mà nó đang làm: làm thế nào về '(1 nếu N% f2 else 0)'? – huon

3

Nếu bạn cần độ chính xác, tránh điểm số học nổi hoàn toàn. Kể từ khi python có số nguyên chính xác tùy ý, bạn có thể tính toán trần của bộ phận bằng cách sử dụng số học số nguyên cơ bản. Giả sử cổ tức và số chia đều dương, cách để làm điều đó là cộng số chia - 1 cho cổ tức trước khi chia. Trong trường hợp của bạn:

fmin = (N + f2 - 1)/f2 

Mở Python 3.x sử dụng toán tử // thay vì / để có được phân chia số nguyên.

Các vấn đề liên quan