2009-07-24 28 views
5

Đây là sự nghi ngờ về biểu diễn bit của các số nguyên đã ký. Ví dụ, khi bạn muốn biểu diễn -1, nó tương đương với phần bù của 2 (+1). Vì vậy, -1 được biểu diễn bằng 0xFFFFFFF. Bây giờ khi tôi thay đổi số của tôi bằng 31 và in kết quả nó sẽ trở lại như -1.Biểu thị số bit của các số âm

signed int a = -1; 
printf(("The number is %d ",(a>>31));//this prints as -1 

Vì vậy, bất kỳ ai cũng có thể giải thích cho tôi cách bit được biểu diễn cho số âm?

Cảm ơn.

+0

Nhìn từ góc độ khác: suy nghĩ về bất kỳ sự dịch chuyển N-bit (ký hiệu mở rộng) nào bằng cách chia cho 2^N, làm tròn XUỐNG (theo hướng trừ cực, không tới 0). Do đó -1 dịch chuyển sang phải (có dấu mở rộng) bất kỳ số lần nào sẽ tiếp tục sản xuất -1. – vladr

Trả lời

10

Khi bit trên cùng bằng không, số là dương. Khi đó là 1, con số này là số âm.

Số âm được dịch chuyển sang phải tiếp tục dịch chuyển "1" ở dạng bit trên cùng để giữ số âm. Đó là lý do tại sao bạn nhận được câu trả lời đó.

Để biết thêm về hai phần bổ sung, hãy xem this Stackoverflow question.


@Stobor chỉ ra rằng một số triển khai C có thể chuyển 0 thành bit cao thay vì 1. [Đã xác minh trong Wikipedia.] Trong Java, đó là sự thay đổi số học đáng kể.

Nhưng đầu ra được đưa ra bởi người hỏi cho thấy trình biên dịch của mình đang thực hiện thay đổi số học.

+0

Nhưng y shud nó in như -1, nó nên in như 1 nghi thức kể từ đầu nhất nhưng là 1 đại diện cho một số âm. –

+1

@Nosredna: bạn cũng nên đề cập rằng hành vi điền-với-dấu-bit được thực hiện cụ thể. – Stobor

+0

Vì nó đại diện cho một số âm, tại sao nó in một số dương? – Nosredna

1

Đây là thao tác dịch số học để giữ bit dấu và thay đổi phần chú giải của một số đã ký.

cổ vũ

8

Tiêu chuẩn C lá nó không xác định liệu sự thay đổi phải của một số âm (nhất thiết phải có chữ ký) số nguyên chuyển zero (shift logic bên phải) hoặc đăng bit (shift số học phải) vào các bit quan trọng nhất. Đó là vào việc thực hiện để lựa chọn.

Do đó, mã di động đảm bảo rằng mã không thực hiện thay đổi đúng về số âm. Hoặc nó chuyển đổi giá trị thành giá trị unsigned tương ứng trước khi dịch chuyển (được đảm bảo sử dụng quyền dịch chuyển logic, đặt zero vào các bit trống), hoặc đảm bảo giá trị là dương, hoặc nó chấp nhận biến thể trong đầu ra.

+0

Hoặc có thể "hoặc" ở bit trên cùng (hoặc bit) sau khi dịch chuyển. – Nosredna

+0

Cảm ơn rất nhiều cho tất cả các câu trả lời.Trò em i m vẫn chưa xóa doyubt của tôi yet.So là nó biên dịch hoặc phần cứng cụ thể? –

+2

@Maddy: nó phụ thuộc vào phần cứng và trình biên dịch.Ví dụ, nếu một CPU cụ thể chỉ có quyền chuyển đổi hợp lý (LSR) và không phải là phép dịch số học (ASR), thì các trình biên dịch cho máy đó sẽ sử dụng LSR và không phải là ASR không tồn tại. Nó cũng phụ thuộc vào trình biên dịch; ngay cả khi một máy có cả ASR và LSR, một nhà biên dịch trình biên dịch có thể quyết định sử dụng LSR cho cả số lượng đã ký và chưa ký, vì bất kỳ lý do nào. Nó có thể nhanh hơn; nó có thể phù hợp với các nền tảng khác, nơi trình biên dịch tương tự cũng chạy; có thể là người viết trình biên dịch không thích ASR. –

1

Về cơ bản có hai loại thay đổi phù hợp. Một sự thay đổi quyền chưa ký và một sự thay đổi quyền đã ký. Một thay đổi bên phải không dấu sẽ chuyển các bit sang bên phải, làm cho bit ít quan trọng nhất bị mất và bit quan trọng nhất được thay thế bằng 0. Với sự dịch chuyển đúng, các bit được dịch sang phải, gây ra ít nhất bit đáng kể bị mất và bit quan trọng nhất cần được bảo toàn. Một sự thay đổi quyền đã ký chia số cho một sức mạnh của hai (tương ứng với số lượng các địa điểm chuyển dịch), trong khi một ca không dấu là một hoạt động chuyển dịch logic.

Toán tử ">>" thực hiện thay đổi bên phải chưa được ký khi loại dữ liệu mà nó hoạt động chưa được ký và nó thực hiện thay đổi đã ký khi loại dữ liệu hoạt động được ký. Vì vậy, những gì bạn cần làm là đưa đối tượng đến một loại số nguyên không dấu trước khi thực hiện thao tác bit để có được kết quả mong muốn.

+0

Không nhất thiết phải là 'thay đổi đã ký' cho các số nguyên đã ký (mặc dù nó thường được thực hiện theo cách đó) - nó phụ thuộc vào trình biên dịch và/hoặc phần cứng. –

+0

Vâng. Đúng rồi. Tôi đã lập trình rất lâu trên máy tính xách tay/máy tính để bàn/máy chủ hoạt động tốt chạy một số biến thể của x86 và biên dịch với GCC, thường dễ dàng quên sự khác biệt giữa những giả định nào hợp lý cho ứng dụng hiện tại và tiêu chuẩn thực sự đảm bảo. –

0

EDIT: Khi dưới đây được viết ra, các mã trong câu hỏi đã được viết như sau:

unsigned int a = -1; 
printf(("The number is %d ",(a>>31));//this prints as -1 

Nếu unsigned int là ít nhất 32 bit rộng, sau đó trình biên dịch của bạn không thực sự cho phép để sản xuất -1 là đầu ra của điều đó (với caveat nhỏ mà bạn nên đúc giá trị unsigned để int trước khi bạn vượt qua nó để printf).

Vì là một int không dấu, gán -1 cho nó phải cho nó giá trị của UINT_MAX (dưới dạng giá trị không âm nhỏ nhất tương đương với -1 modulo UINT_MAX + 1). Miễn là int chưa ký có ít nhất 32 bit trên nền tảng của bạn, kết quả của việc dịch chuyển số lượng chưa ký phải bằng 31 sẽ là UINT_MAX chia cho 2^31, mà phải vừa với int. (Nếu int unsigned là 31 bit hoặc ngắn hơn, nó có thể sản xuất bất cứ điều gì nó thích bởi vì kết quả của sự thay đổi là không xác định).

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