2011-07-27 40 views
9

Tôi đang triển khai giải mã các số nguyên được nén BER và gần đây tôi đã tìm thấy một hành vi JavaScript lạ liên quan đến hoạt động bitwise với số nguyên lớn.Hoạt động bitwise với số nguyên lớn

ví dụ .:

var a = 17516032;   // has 25 bits 
alert(a << 7)    // outputs -2052915200 
alert(a * 128)    // outputs 2242052096 
alert(2242052096 >> 16) // outputs -31325 
alert(2242052096/65536) // outputs 34211 

Trong khi thực hiện giải pháp đầu tiên (nhân thay vì dịch trái) là chấp nhận được, thứ hai là không.

Tại sao điều đó xảy ra? Làm thế nào để chịu đựng với nó?

+0

Tôi không hiểu tại sao bộ phận sẽ không được chấp nhận? – Guffa

+0

@Guffa Tôi cần một số cách tiếp cận chung, không chỉ cho các số nguyên 32 bit. –

+0

Phân chia không được thực hiện trên các số nguyên, nó được thực hiện trên các số dấu phẩy động, vì vậy tôi không hiểu đối số của bạn. Bên cạnh đó, một số điểm nổi chính xác gấp đôi chỉ có thể đại diện cho một số nguyên 53 bit, do đó, đó là không nhiều anyway nếu bạn muốn giải mã BER-nén số. – Guffa

Trả lời

7

17516032 trong nhị phân là 00000001000010110100011000000000. Chuyển sang bên trái 7 cung cấp cho bạn 10000101101000110000000000000000. Điều này tương đương với -2052915200 trong two's complement (đó là cách gần như tất cả các máy tính đại diện cho số âm).

>> là thay đổi phù hợp đã ký. Điều đó có nghĩa rằng bit ngoài cùng bên trái (xác định dấu hiệu của một số) sẽ được chuyển sang bên trái.

ví dụ:

1100 >> 2 == 1111 
0111 >> 2 == 0001 

Nếu bạn muốn làm một sự thay đổi unsigned (mà bỏ qua các bit dấu), sử dụng >>> mà sẽ zero-điền đầu bên trái của bitstring.

+0

Vậy đó, cảm ơn! Bất kỳ ý tưởng tại sao sự thay đổi trái tạo ra kết quả kỳ lạ như vậy? –

+0

Không sao cả. Đã chỉnh sửa câu trả lời của tôi để bao gồm điều đó. – tskuzzy

3

Các toán tử bitwise hoạt động trên các số nguyên 32 bit, trong khi phép nhân và phép chia hoạt động trên các số dấu phẩy động.

Khi bạn thay đổi một số, nó được chuyển đổi từ một số dấu phẩy động thành số nguyên 32 bit trước hoạt động và chuyển trở lại số dấu phẩy động sau khi thao tác. Số 2242052096 có bộ bit 32, do đó, nó là số âm khi được chuyển đổi và từ số nguyên 32 bit.

Nhà điều hành dịch chuyển phải >> không thay đổi dấu của giá trị, tức là các bit được dịch chuyển từ bên trái có cùng giá trị với bit dấu. Sử dụng toán tử thay đổi bên phải >>> để thay đổi bit bằng không.

tham khảo: MDN: Bitwise operators

2

(2242052096/65536) == (2242052096 >>> 16)

Lưu ý sự thay đổi khác nhau.

1

Javascript thường đại diện cho các số là điểm nổi (chính xác kép).

Hầu như tất cả các hoạt động bitwise chuyển thành số nguyên 32 bit đã ký, làm bất cứ điều gì chúng sẽ làm, sau đó xử lý kết quả dưới dạng số nguyên 32 bit đã ký khi chuyển đổi lại.

Ngoại lệ là >>> xử lý kết quả là không ký số nguyên 32 bit khi chuyển đổi lại.

Vì vậy:

  • thay đổi thích hợp có thể được thực hiện để làm việc đơn giản bằng cách sử dụng >>> thay vì >>;
  • a * 128 cung cấp câu trả lời mong đợi vì nó không bao giờ được chuyển đổi thành số nguyên 32 bit đã ký ở vị trí đầu tiên - đó chỉ là phép nhân dấu phẩy động;
  • a << 7 đưa ra câu trả lời không mong muốn vì nó được chuyển thành số nguyên 32 bit đã ký và sau đó bạn chuyển 1 vào bit dấu, dẫn đến giá trị 32 bit đã ký âm.

Không có một <<<, nhưng nếu bạn muốn viết chuyển trái của bạn như là một sự thay đổi, bạn có thể sử dụng

(a << 7) >>> 0 

để có được câu trả lời mong đợi (các >>> 0 hiệu quả phôi đã ký 32 giá trị bit tới giá trị 32 bit không dấu).

+0

Rất đẹp. Cám ơn vì sự giải thích! –

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