Python kiểm tra tràn số nguyên

Là một nhà khoa học dữ liệu, bạn sẽ dành nhiều thời gian hơn để chơi với các con số so với hầu hết các lập trình viên. Do đó, bạn nên hiểu cách các số được biểu diễn trong máy tính và cách các biểu diễn đó có thể khiến bạn gặp rắc rối như thế nào

Bài học này được chia thành hai phần. Trong phần đầu tiên, chúng ta sẽ đề cập đến những kiến ​​thức cơ bản về cách máy tính nghĩ về các con số và những vấn đề có thể phát sinh với hai biểu diễn số chính mà bạn sẽ sử dụng. Trong phần thứ hai, chúng ta sẽ thảo luận khi nào bạn cần lo lắng về những mối nguy hiểm này [a] khi sử dụng vanilla Python và [b] khi sử dụng

# Regular Python:
%timeit sum[range[1000000]]
4 và
# Regular Python:
%timeit sum[range[1000000]]
5

Hai Hạng Số. Số nguyên và số dấu phẩy động

Nói rộng ra, máy tính có hai cách biểu diễn số. số nguyên và số dấu chấm động. Trong hầu hết các khóa học giới thiệu về khoa học máy tính, học sinh được dạy rằng số nguyên dành cho… à, số nguyên [số nguyên] và số dấu phẩy động dành cho số có dấu thập phân. Điều đó đúng với một điểm. Nhưng bên dưới, số nguyên và số dấu phẩy động hoạt động theo những cách rất khác nhau và có những mối nguy hiểm riêng biệt khi làm việc với cả hai

Để tìm hiểu thông tin chi tiết về cách thức hoạt động của số nguyên và số dấu phẩy động, vui lòng xem lại các tài liệu sau [những giải thích này rất hay và không có lý do gì để cố gắng viết các giải thích của riêng tôi khi chúng tồn tại]. Sau đó tiếp tục đến phần bên dưới về các mối nguy hiểm dành riêng cho Python

số nguyên

Để xem một cuộc thảo luận tuyệt vời về số nguyên [và cạm bẫy chính của chúng. tràn số nguyên], vui lòng xem video này

Nếu sau khi xem bạn muốn tìm hiểu thêm, Chương 7 và 8 của Code. Ngôn ngữ ẩn của phần cứng và phần mềm máy tính của Charles Petzold đi vào số nguyên rất chi tiết

Số dấu phẩy động

Số nguyên, như một kiểu dữ liệu, thật tuyệt vời. Chúng chính xác và khá trực quan. Nhưng họ cũng có điểm yếu. cụ thể là, chúng không thể biểu thị các số có dấu thập phân [mà chúng tôi luôn sử dụng] và chúng không thể biểu thị các số thực sự lớn

Vì vậy, làm thế nào để chúng ta đối phó với số thập phân và số thực sự lớn?

Để tìm hiểu về số dấu phẩy động, vui lòng

  • Xem video này

  • Đọc này

Mối nguy số trong Python, Numpy và Pandas

Vì vậy, nói chung, những mối nguy hiểm với số nguyên và dấu chấm động là

  • Số nguyên có thể bị tràn, dẫn đến tình huống cộng hai số lớn sẽ tạo ra… số âm

  • Các số dấu phẩy động luôn không chính xác, dẫn đến các tình huống trong đó các lỗi toán học rõ ràng đơn giản [e. g. , trong Python

    # Regular Python:
    %timeit sum[range[1000000]]
    
    6 trả về
    # Regular Python:
    %timeit sum[range[1000000]]
    
    7]

  • Số dấu phẩy động chỉ có thể theo dõi rất nhiều chữ số ở đầu, nghĩa là bạn không thể làm việc với CẢ HAI số dấu phẩy động rất lớn và rất nhỏ cùng một lúc [e. g. , trong Python,

    # Regular Python:
    %timeit sum[range[1000000]]
    
    8 trả về
    # Regular Python:
    %timeit sum[range[1000000]]
    
    9]

Nhưng khi nào chúng ta cần phải lo lắng về những vấn đề này?

Câu trả lời là nó phụ thuộc vào việc bạn đang sử dụng Python thông thường, vani hay

# Regular Python:
%timeit sum[range[1000000]]
4 /
# Regular Python:
%timeit sum[range[1000000]]
5

Tràn số nguyên trong Python

Python được coi là một ngôn ngữ thân thiện và một biểu hiện của điều đó là trong vanilla Python, bạn không thể làm tràn số nguyên của mình. Đó là bởi vì bất cứ khi nào Python thực hiện một phép tính số nguyên, nó sẽ dừng lại để kiểm tra xem số nguyên trong câu hỏi của bạn đã được phân bổ đủ bit để lưu trữ kết quả hay chưa, và nếu không, nó chỉ thêm nhiều bit hơn. Vì vậy, nếu bạn làm toán với một số nguyên không vừa với 64 bit, nó sẽ chỉ phân bổ nhiều bit hơn cho số nguyên đó

________số 8

# Here's a really big integer
x = 2**63

# Regular Python:
%timeit sum[range[1000000]]
0

# Regular Python:
%timeit sum[range[1000000]]
1

# Regular Python:
%timeit sum[range[1000000]]
0

# Regular Python:
%timeit sum[range[1000000]]
3

Nhìn thấy?

Tràn số nguyên trong numpy và pandas

Vấn đề với những gì Python làm với số nguyên là, trong khi thuận tiện, nó lại chậm. Yêu cầu Python cộng hai số nguyên không chỉ yêu cầu máy tính cộng hai số nguyên; . Điều này làm cho việc thêm số nguyên trong Python chậm hơn rất nhiều so với mức có thể. Giống như… chậm hơn 10 lần

Đó là lý do tại sao các thư viện như

# Regular Python:
%timeit sum[range[1000000]]
4 và
# Regular Python:
%timeit sum[range[1000000]]
5 — được thiết kế để đạt hiệu suất khi làm việc với các bộ dữ liệu khổng lồ — không kiểm tra lỗi tràn số nguyên. Điều này làm cho chúng nhanh hơn nhiều, nhưng nếu bạn thêm hai số nguyên thực sự lớn vào
# Regular Python:
%timeit sum[range[1000000]]
4 [hoặc thêm các số chẵn nhỏ vào một số thực sự lớn] và kết quả lớn hơn so với những gì vừa với các bit có sẵn, bạn sẽ chỉ nhận được một số âm.

Nhanh hơn bao nhiêu? . Một số khác biệt này đến từ những thứ khác ngoài kiểm tra tràn, nhưng điều này cho bạn cảm giác về chi phí hiệu suất để làm cho số nguyên an toàn hơn trong Python thông thường

# Regular Python:
%timeit sum[range[1000000]]
8

# Regular Python:
%timeit sum[range[1000000]]

# Regular Python:
%timeit sum[range[1000000]]
0

# Regular Python:
%timeit sum[range[1000000]]
1

# Here's a really big integer
x = 2**63
0

# Here's a really big integer
x = 2**63
1

Nhưng như tôi đã nói, trong khi nó có thể nhanh, nó cũng có thể nguy hiểm.

# Here's a really big integer
x = 2**63
2

# Here's a really big integer
x = 2**63
3

# Here's a really big integer
x = 2**63
2

# Here's a really big integer
x = 2**63
5

# Here's a really big integer
x = 2**63
6

# Here's a really big integer
x = 2**63
7

# Here's a really big integer
x = 2**63
6

# Here's a really big integer
x = 2**63
9

Điều quan trọng là phải hiểu rằng với

# Regular Python:
%timeit sum[range[1000000]]
4 và
# Regular Python:
%timeit sum[range[1000000]]
5, bạn kiểm soát kích thước của số nguyên và do đó bạn có thể tạo ra số nguyên lớn như thế nào trước khi gặp sự cố tràn. Theo mặc định,
# Regular Python:
%timeit sum[range[1000000]]
4 sẽ làm cho số nguyên của bạn có kích thước phù hợp với bộ xử lý hệ thống của bạn [thường là 64 bit trên máy tính hiện đại, nhưng đôi khi là 32 bit trên máy tính cũ hơn]. Nhưng
# Regular Python:
%timeit sum[range[1000000]]
4 cũng cho phép bạn tạo các mảng 16 bit [
# Regular Python:
%timeit sum[range[1000000]]
10], 32 bit [
# Regular Python:
%timeit sum[range[1000000]]
11] hoặc 64 bit [
# Regular Python:
%timeit sum[range[1000000]]
12]. Điều này có thể rất hữu ích khi làm việc với các bộ dữ liệu lớn. số nguyên nhỏ hơn chiếm ít bộ nhớ hơn và đôi khi các phép tính với số nguyên nhỏ hơn có thể nhanh hơn do một số điều phức tạp về cách máy tính sử dụng bộ nhớ. Nhưng nếu bạn sử dụng kích thước số nguyên nhỏ hơn, thì bạn thực sự cần phải cẩn thận với số tràn của mình.
# Regular Python:
%timeit sum[range[1000000]]
10 chỉ có thể lưu số lên tới 32.768

# Regular Python:
%timeit sum[range[1000000]]
00

# Regular Python:
%timeit sum[range[1000000]]
01

# Regular Python:
%timeit sum[range[1000000]]
00

# Regular Python:
%timeit sum[range[1000000]]
03

Ngoài ra, lưu ý rằng

# Regular Python:
%timeit sum[range[1000000]]
4 và
# Regular Python:
%timeit sum[range[1000000]]
5 có các số nguyên "không dấu" [
# Regular Python:
%timeit sum[range[1000000]]
16,
# Regular Python:
%timeit sum[range[1000000]]
17,
# Regular Python:
%timeit sum[range[1000000]]
18]. Đây giống như các số nguyên thông thường, ngoại trừ chúng không phân bổ một nửa giá trị của chúng cho các số âm, vì vậy giới hạn trên của chúng gấp 2 lần số nguyên thông thường có cùng kích thước. Tuy nhiên, nói chung, tốt nhất là nên tránh
# Regular Python:
%timeit sum[range[1000000]]
19, vì nó quá dễ bị tràn bằng cách chạm đáy các giá trị mà nó có thể chịu được [i. e. , xuống dưới 0]

# Regular Python:
%timeit sum[range[1000000]]
04

# Regular Python:
%timeit sum[range[1000000]]
05

# Regular Python:
%timeit sum[range[1000000]]
04

# Regular Python:
%timeit sum[range[1000000]]
07

# Regular Python:
%timeit sum[range[1000000]]
08

# Regular Python:
%timeit sum[range[1000000]]
09

# Regular Python:
%timeit sum[range[1000000]]
08

# Regular Python:
%timeit sum[range[1000000]]
11

Độ chính xác của dấu phẩy động

Thật không may, mặc dù vanilla Python có thể bảo vệ bạn khỏi tràn số nguyên, nhưng nó không thể làm bất cứ điều gì về độ chính xác của dấu phẩy động. Cho dù bạn có đang sử dụng

# Regular Python:
%timeit sum[range[1000000]]
4 hay không, thì bạn vẫn mắc kẹt với những thứ này

# Regular Python:
%timeit sum[range[1000000]]
12

# Regular Python:
%timeit sum[range[1000000]]
13

# Regular Python:
%timeit sum[range[1000000]]
12

# Regular Python:
%timeit sum[range[1000000]]
15

# Regular Python:
%timeit sum[range[1000000]]
16

# Regular Python:
%timeit sum[range[1000000]]
17

# Regular Python:
%timeit sum[range[1000000]]
16

# Regular Python:
%timeit sum[range[1000000]]
19

Nhưng bạn cũng nhận được những điều kỳ lạ như 7. 5 làm tròn lên và 10. 5 làm tròn xuống

# Regular Python:
%timeit sum[range[1000000]]
00

# Regular Python:
%timeit sum[range[1000000]]
01

# Regular Python:
%timeit sum[range[1000000]]
00

# Regular Python:
%timeit sum[range[1000000]]
03

# Regular Python:
%timeit sum[range[1000000]]
04

# Regular Python:
%timeit sum[range[1000000]]
05

# Regular Python:
%timeit sum[range[1000000]]
04

# Regular Python:
%timeit sum[range[1000000]]
07

Vì vậy, chỉ cần nhớ. bất cứ điều gì bạn đang làm với các số dấu phẩy động, các bài kiểm tra chính xác, sắc bén có thể làm những điều kỳ lạ

Nếu bạn muốn bảo vệ chống lại điều này, hãy cân nhắc sử dụng hàm

# Here's a really big integer
x = 2**63
01 từ thư viện
# Regular Python:
%timeit sum[range[1000000]]
4, hàm này sẽ trả về
# Regular Python:
%timeit sum[range[1000000]]
9 nếu hai đối số mà nó truyền vào thực sự gần nhau. [rất gần, ý tôi là
# Here's a really big integer
x = 2**63
04 kiểm tra xem \[absolute[a - b] where the relative tolerance [\[rtol\]] is \[10^{-5}\], and the absolute tolerance [\[atol\]] is \[10^{-8}\] by default. You can also change these tolerances if you want, as shown in the help file].

# Regular Python:
%timeit sum[range[1000000]]
08

# Regular Python:
%timeit sum[range[1000000]]
09

# Regular Python:
%timeit sum[range[1000000]]
08

# Regular Python:
%timeit sum[range[1000000]]
19

Số ngẫu nhiên

Một điều kỳ lạ khác về cách máy tính nghĩ về các con số là mặc dù có vẻ như máy tính luôn tạo ra các số ngẫu nhiên cho bạn — ví dụ: máy tính của bạn sẵn lòng cung cấp cho bạn một mẫu dữ liệu con ngẫu nhiên nếu bạn yêu cầu — thực tế là vì máy tính . Thay vào đó, chúng tạo ra các số giả ngẫu nhiên [PRNG], là các chuỗi số có tất cả các thuộc tính thống kê mà chúng ta muốn từ các số ngẫu nhiên, nhưng thực tế được tạo ra một cách xác định

Đối với các nhà khoa học dữ liệu, điều này thực sự khá hữu ích, bởi vì chúng ta có thể tận dụng điều này để tạo mã vừa “ngẫu nhiên” vừa có thể tái tạo. Điều này được thực hiện bằng cách sử dụng “hạt giống. ”

Để tạo các số giả ngẫu nhiên, các máy tính bắt đầu bằng một số bắt đầu, có thể giống như “số giây kể từ khi hệ điều hành Unix được tạo. ” Sau đó, nó cung cấp số ban đầu đó thông qua một loạt các thao tác. Ví dụ: trong các PRNG đầu tiên, bạn sẽ bắt đầu với một số có bốn chữ số, bình phương nó, giữ bốn chữ số ở giữa của kết quả, sau đó lặp đi lặp lại quy trình này. Kết quả của quá trình này, sau khi đủ số lần lặp, sẽ được phân phối đồng đều trên khoảng [0, 9999]. [Ngày nay các thuật toán phức tạp hơn nhiều, nhưng nguyên tắc thường giống nhau - lấy một số, thực hiện các phép tính kỳ lạ, lấy một tập hợp con các chữ số, lặp lại]

Bởi vì điều này là xác định, nếu bạn biết số bắt đầu với máy tính, bạn có thể dự đoán tất cả các số tiếp theo. Điều này hóa ra lại rất tệ đối với an ninh mạng, nhưng lại tốt cho khoa học dữ liệu, bởi vì nếu chúng ta chỉ định số bắt đầu đó, thì chúng ta có thể tạo lại "sự ngẫu nhiên" tương tự vào ngày mai mà chúng ta có được hôm nay

Trong Python, bạn có thể tạo ngẫu nhiên một cách nhanh chóng với thư viện

# Here's a really big integer
x = 2**63
05 [lưu ý rằng cũng có một thư viện không gọn gàng cho các số ngẫu nhiên có tên là
# Here's a really big integer
x = 2**63
06, nhưng tôi nghĩ hầu hết mọi người trong khoa học dữ liệu đều sử dụng thư viện ngẫu nhiên
# Regular Python:
%timeit sum[range[1000000]]
4 vì nó nhanh chóng tạo ra các mảng số ngẫu nhiên]

# Regular Python:
%timeit sum[range[1000000]]
32

# Regular Python:
%timeit sum[range[1000000]]
33

# Regular Python:
%timeit sum[range[1000000]]
32

# Regular Python:
%timeit sum[range[1000000]]
35

# Regular Python:
%timeit sum[range[1000000]]
36

# Regular Python:
%timeit sum[range[1000000]]
37

# Regular Python:
%timeit sum[range[1000000]]
36

# Regular Python:
%timeit sum[range[1000000]]
39

Nhưng nếu chúng tôi muốn khả năng tái tạo, chúng tôi có thể "gieo" trình tạo số ngẫu nhiên của mình, điều đó có nghĩa là chúng tôi đang đặt số bắt đầu và do đó đảm bảo rằng chúng tôi luôn nhận được các số giống nhau. Vì vậy, đây là một chuỗi được tạo khi hạt giống được đặt thành 42

# Regular Python:
%timeit sum[range[1000000]]
80

# Regular Python:
%timeit sum[range[1000000]]
81

# Regular Python:
%timeit sum[range[1000000]]
82

Và bây giờ chúng tôi đặt hạt giống BACK thành 42 và chúng tôi sẽ nhận được cùng một chuỗi các số rõ ràng là ngẫu nhiên

# Regular Python:
%timeit sum[range[1000000]]
83

# Regular Python:
%timeit sum[range[1000000]]
81

# Regular Python:
%timeit sum[range[1000000]]
82

Việc gieo hạt cũng ảnh hưởng đến hành vi của các hàm sử dụng tính ngẫu nhiên, ngay cả khi bạn không nhìn thấy các số ngẫu nhiên một cách rõ ràng. Ví dụ: nếu chúng ta xáo trộn một mảng có nhiều mảng bằng hàm có nhiều mảng bằng hàm

# Here's a really big integer
x = 2**63
08, việc đặt hạt giống trước sẽ mang lại cho chúng ta kết quả có thể lặp lại

# Regular Python:
%timeit sum[range[1000000]]
86

# Regular Python:
%timeit sum[range[1000000]]
87

# Regular Python:
%timeit sum[range[1000000]]
86

# Regular Python:
%timeit sum[range[1000000]]
89

# Regular Python:
%timeit sum[range[1000000]]
0

# Regular Python:
%timeit sum[range[1000000]]
87

# Regular Python:
%timeit sum[range[1000000]]
0

# Regular Python:
%timeit sum[range[1000000]]
89

Lưu ý thận trọng

Một vài lưu ý cảnh báo về trình tạo số ngẫu nhiên

  • Các chức năng khác nhau có thể dựa vào các trình tạo số ngẫu nhiên khác nhau. Ví dụ: thư viện chuẩn Python có thư viện

    # Here's a really big integer
    x = 2**63
    
    06 và numpy có thư viện
    # Here's a really big integer
    x = 2**63
    
    05. Nếu bạn đặt nguồn gốc cho trình tạo số ngẫu nhiên của thư viện tiêu chuẩn, sau đó sử dụng hàm sử dụng trình tạo số ngẫu nhiên
    # Regular Python:
    %timeit sum[range[1000000]]
    
    4, bạn sẽ không nhận được kết quả có thể lặp lại

  • Một số thư viện bạn sẽ sử dụng trong Python không sử dụng trình tạo số ngẫu nhiên Python hoặc numpy; . Điều này có thể gây khó khăn, hoặc, tùy thuộc vào cách thư viện được viết, không thể đặt hạt giống

  • Mặc dù đặt hạt giống cho trình tạo số ngẫu nhiên gọn gàng sẽ mang lại cho bạn kết quả có thể lặp lại trên các hệ thống máy tính, nhưng điều này không đúng với tất cả các trình tạo số ngẫu nhiên. Một số [đặc biệt là những cái được viết bằng C] sẽ chỉ có thể sao chép được đối với một kiến ​​trúc máy tính nhất định. Nếu bạn chia sẻ mã Mac của mình với người dùng Windows, bạn có thể không nhận được kết quả có thể lặp lại

Vì vậy, các hạt ngẫu nhiên rất hữu ích, nhưng nếu bạn thực sự cần khả năng tái tạo, hãy đảm bảo rằng bạn đã kiểm tra mã của mình bằng cách chạy đi chạy lại mã đó [và có thể trên các máy tính khác nhau] để đảm bảo mã được định cấu hình chính xác

Muốn tìm hiểu thêm?

Tôi đánh giá cao video tuyệt vời này

Số ngẫu nhiên và mật mã

Khả năng dự đoán của các trình tạo số giả ngẫu nhiên rất tốt cho các nhà khoa học dữ liệu, nhưng nó rất nguy hiểm đối với mật mã học. Nếu bạn quan tâm đến cách mọi người giải quyết vấn đề này khi bảo mật là quan trọng, bạn có thể tìm hiểu về cách thức hoạt động của Internet trên đèn dung nham tại đây

Làm cách nào để phát hiện python tràn số nguyên?

Viết hàm “C”, int addOvf[int* result, int a, int b] Nếu không có tràn, hàm sẽ đặt kết quả = sum a+b .

Có tràn số nguyên tồn tại trong python?

Trong python 2, thực tế có hai loại số nguyên. int và long , trong đó int là số nguyên có độ chính xác cố định kiểu C và long là số nguyên có độ chính xác tùy ý. Các hoạt động được tự động thăng cấp thành long nếu int không đủ, vì vậy không có nguy cơ bị tràn .

Làm cách nào để kiểm tra xem float có phải là số nguyên python không?

Kiểm tra xem float có phải là số nguyên không. is_integer[] .

Làm cách nào để kiểm tra xem đầu vào có phải là số nguyên python không?

sử dụng str. phương thức isdigit[] để kiểm tra xem đầu vào của người dùng có phải là số nguyên không. Phương thức isdigit[] sẽ trả về True cho tất cả các giá trị nguyên dương và Sai cho tất cả các số không phải là số, số dấu phẩy động hoặc số âm

Chủ Đề