2016-01-20 20 views
17

Hôm nay tôi vừa khám phá thú vị trong khi kiểm tra những gì xảy ra khi tính toán bitwisely trong php như INF^0 (^ => Bitwise Operator for Exclusive OR (XOR)) giá trị âm trong hệ thống 64 bit.Giá trị vô hạn của PHP trong Bitwise Operations trả về các giá trị lạ

Nhưng sau đó tôi đã hỏi bản thân mình: "Tại sao kết quả sẽ tiêu cực trong XOR khi 'infinit tích cực' có nghĩa là 9223372036854775807 (63 Bits trên 1 với một 0 hàng đầu) và 0 (64 Bits trên 0 =>0 xor 0 = 0) gì Mặc dù giá trị vô hạn của PHP là gì và giá trị âm là gì (đúng?) khi tôi sử dụng "cực âm" (A hàng đầu 1 đối với một số 0 hàng đầu trên 0 =>1 xor 0 = 1? ".

Một điểm thú vị khác là điều này chỉ xảy ra trên phiên bản PHP 5.5.9-1, và không ví dụ như trên 5.3.x. và 5.6.x (nơi tôi đã thử nghiệm nó)! Có thể ai đó có ý tưởng điều gì xảy ra ở đó? Thử nghiệm nó trên ba phiên bản nhưng chỉ mỏ (5.5.9-1) mang đến những kết quả:

Bitwise operations

Chỉ cần để cho các bạn biết, nó chỉ là một playaround trừu tượng tôi đã làm cho vui nhưng tôi thấy nó là hấp dẫn. Có lẽ ai đó có thể giúp đỡ ở đây hoặc giải thích cho tôi một ý nghĩ sai lầm tôi có? Chỉ cần cho tôi biết nếu ai đó cần thêm thông tin về bất cứ điều gì!

EDIT: Theo đó để jbafford nó sẽ là tuyệt vời để có được một answere hoàn chỉnh, vì vậy tôi sẽ chỉ trích ông: why does 5.5 and 5.6 result in PHP_INT_MIN, and everything else return 0?

+3

'-9223372036854775808' là giá trị âm lớn nhất có thể __cho một số nguyên (64 bit) __....' INF' không phải là số nguyên, nhưng [float float 8.7] (https://en.wikipedia.org/ wiki/IEEE_754-1985) –

+1

Bạn có nghĩ rằng vấn đề có lẽ là so sánh bit từ 'float (INF)' với 'int (0)'? Bạn có biết cách này hoạt động không? –

+3

Bạn đang sử dụng các hoạt động bitwise trên giá trị float 64 bit, nhưng sử dụng các hoạt động bitwise xử lý giá trị như thể nó là một giá trị nguyên 64 bit 'Các toán tử bitwise cho phép đánh giá và thao tác các bit cụ thể trong một __integer __.' ... .. do đó nó là một so sánh fallacious. Ops bitwise không kiểm tra xem bạn có đang thực thi chúng với float hay không, bởi vì chúng quan tâm ở mức bit, nhưng chúng sẽ thiết lập kiểu dữ liệu kết quả thành một số nguyên –

Trả lời

7

Trước hết, ^ bản thân không phải là điều đặc biệt ở đây. Nếu bạn XOR bất cứ điều gì với số không, hoặc HOẶC bất cứ điều gì với số không, bạn chỉ cần lấy lại câu trả lời ban đầu. Những gì bạn thấy ở đây không phải là một phần của hoạt động, mà là những gì xảy ra trước khi hoạt động: các toán tử bitwise lấy các số nguyên, vì vậy PHP chuyển đổi float thành một số nguyên. Đó là trong chuyển đổi float-to-integer mà hành vi lạ xuất hiện, và nó không dành riêng cho các toán tử bitwise. Nó cũng xảy ra cho (int), ví dụ.

Tại sao nó tạo ra các kết quả lạ này? Đơn giản chỉ vì đó là những gì mã PHP PHP được viết trong khi tạo ra một float cho một số nguyên. Trong tiêu chuẩn C, hành vi của C đối với chuyển đổi float-to-integer là không xác định cho các giá trị đặc biệt INF, -INFNAN (hoặc chính xác hơn, đối với "bộ phận tách rời" một số nguyên không thể đại diện: §6.3.1.4). Điều này undefined behaviour có nghĩa là trình biên dịch là miễn phí để làm bất cứ điều gì nó muốn. Nó chỉ xảy ra trong trường hợp này mã mà nó tạo ra tạo ra giá trị số nguyên tối thiểu ở đây, nhưng không có sự đảm bảo nào sẽ luôn xảy ra và nó không nhất quán trên các nền tảng hoặc trình biên dịch. Tại sao hành vi thay đổi giữa 5,4 và 5,5? Bởi vì mã PHP để chuyển đổi phao sang số nguyên changed to always perform a modulo conversion.Điều này cố định hành vi không xác định cho các số dấu phẩy động rất lớn, nhưng nó vẫn không kiểm tra các giá trị đặc biệt, vì vậy trong trường hợp đó nó vẫn tạo ra hành vi không xác định, chỉ hơi khác thời gian này.

Trong PHP 7, tôi quyết định dọn dẹp khu vực này của hành vi của PHP với Integer Semantics RFC, mà làm cho séc PHP cho các giá trị đặc biệt (INF, -INFNAN) và chuyển đổi một cách nhất quán: họ luôn luôn chuyển đổi để nguyên 0. Không còn hành vi không xác định tại nơi làm việc ở đây.


Ví dụ, một chương trình thử nghiệm tôi đã viết trong C để cố gắng chuyển đổi Infinity thành một số nguyên (đặc biệt là một C long) có kết quả khác nhau trên 32-bit và 64-bit được xây dựng. Bản dựng 64 bit luôn sản xuất -9223372036854775808, giá trị số nguyên tối thiểu, trong khi bản dựng 32 bit luôn tạo ra 0. Hành vi này giống với GCC và clang, vì vậy tôi đoán cả hai đều sản xuất mã máy rất giống nhau.

Nếu bạn đã cố gắng để chuyển đổi một phao để một số nguyên, và giá trị của phao đó là quá lớn để vừa trong một số nguyên (ví dụ PHP_INT_MAX * 2, hoặc PHP_INT_MIN * 2), kết quả là không xác định. PHP 5.5 làm cho kết quả phù hợp, mặc dù không trực quan (nó hoạt động nếu phao được chuyển đổi thành một số nguyên rất lớn, và các bit quan trọng nhất đã bị loại bỏ).

+0

Đó là câu trả lời tôi đang tìm kiếm! Cảm ơn rất nhiều :-) –

+0

Tôi rất vui vì bạn thích nó! (Mặc dù tôi không thực sự quan tâm đến nó, bạn có thể muốn trao tiền thưởng.) – Andrea

4

bạn float(INF) được ngầm Casted đến một Integer.

và XOR bằng 0 không thay đổi tham số đầu tiên. Vì vậy, về cơ bản đây chỉ là một diễn viên từ float đến int mà là undefined cho các giá trị mà không phải là trong phạm vi số nguyên. (Cho tất cả các giá trị khác sẽ bị cắt bớt đối với zero)

https://3v4l.org/52bA5

+3

Điều này không thực sự trả lời phần thú vị hơn của câu hỏi, đó là lý do tại sao 5.5 và 5.6 dẫn đến PHP_INT_MIN và mọi thứ khác trả về 0? – jbafford

+0

có thể vì đó là những gì hàm C cơ bản trả về. Nhưng kể từ khi kết quả là không xác định nó có thể là bất kỳ số tùy ý và nó vẫn sẽ là một kết quả "chính xác" – belst

+2

Vâng, vâng, tất nhiên. Nhưng một câu trả lời thú vị sẽ là * những gì cụ thể * thay đổi (và tại sao) trong 5.5 và 7. – jbafford

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