Số nguyên đã ký so với chưa ký


395

Tôi có đúng không khi nói sự khác biệt giữa số nguyên có dấu và không dấu là:

  1. Chưa ký có thể giữ giá trị dương lớn hơn và không có giá trị âm.
  2. Unsign sử dụng bit đầu là một phần của giá trị, trong khi phiên bản đã ký sử dụng bit trái nhất để xác định xem số đó là dương hay âm.
  3. số nguyên đã ký có thể chứa cả số dương và số âm.

Còn sự khác biệt nào nữa không?


6
0 không dương cũng không âm , nên sử dụng thuật ngữ giá trị không âm thay vì giá trị dương cho các số nguyên không dấu là phù hợp hơn .
Daniel

Câu trả lời:


344

Chưa ký có thể giữ giá trị dương lớn hơn và không có giá trị âm.

Đúng.

Unsign sử dụng bit đầu là một phần của giá trị, trong khi phiên bản đã ký sử dụng bit trái nhất để xác định xem số đó là dương hay âm.

Có nhiều cách khác nhau để biểu diễn số nguyên đã ký. Cách dễ nhất để hình dung là sử dụng bit ngoài cùng bên trái làm cờ ( dấu hiệu và cường độ ), nhưng phổ biến hơn là bổ sung của hai . Cả hai đều được sử dụng trong hầu hết các bộ vi xử lý hiện đại - dấu phẩy động sử dụng dấu và độ lớn, trong khi số học số nguyên sử dụng phần bù hai.

số nguyên đã ký có thể chứa cả số dương và số âm.

Đúng


Tôi không chắc đây có phải là văn bản chính xác không nhưng tôi đã tìm thấy một liên kết khác. Chuyển đến trang thứ 9 của PDF (thực ra là trang thứ 38 của cuốn sách) và bạn có thể thấy phần được gọi là Biểu diễn dữ liệu (Phần 1.3). Nó có lời giải thích của tất cả những điều đã nói ở trên. lms.uop.edu.jo/lms/pluginfile.php/2420/mod_resource/content/1/ mẹo
WeirdElfB0y

92

Tôi sẽ đi vào sự khác biệt ở cấp độ phần cứng, trên x86. Điều này chủ yếu là không liên quan trừ khi bạn viết trình biên dịch hoặc sử dụng ngôn ngữ hợp ngữ. Nhưng thật tuyệt khi biết điều đó.

Thứ nhất, x86 có nguồn gốc hỗ trợ cho các bổ sung của hai đại diện của số ký. Bạn có thể sử dụng các đại diện khác nhưng điều này sẽ yêu cầu nhiều hướng dẫn hơn và thường lãng phí thời gian của bộ xử lý.

"Hỗ trợ bản địa" nghĩa là gì? Về cơ bản, ý tôi là có một bộ hướng dẫn bạn sử dụng cho các số không dấu và một bộ khác mà bạn sử dụng cho các số đã ký. Các số chưa ký có thể nằm trong cùng các thanh ghi như các số đã ký và thực sự bạn có thể trộn các hướng dẫn đã ký và chưa ký mà không làm bộ xử lý lo lắng. Tùy thuộc vào trình biên dịch (hoặc lập trình viên lắp ráp) để theo dõi xem một số có được ký hay không và sử dụng các hướng dẫn thích hợp.

Thứ nhất, hai số bù của hai thuộc tính có phép cộng và phép trừ giống như với số không dấu. Nó không có sự khác biệt cho dù các con số là tích cực hay tiêu cực. (Vì vậy, bạn chỉ cần đi trước và ADDSUBcon số của bạn mà không cần lo lắng.)

Sự khác biệt bắt đầu cho thấy khi so sánh. x86 có một cách đơn giản để phân biệt chúng: trên / dưới biểu thị một so sánh không dấu và lớn hơn / nhỏ hơn chỉ ra một so sánh đã ký. (Ví dụ: JAE"Nhảy nếu trên hoặc bằng" và không dấu.)

Ngoài ra còn có hai bộ hướng dẫn nhân và chia để đối phó với các số nguyên đã ký và không dấu.

Cuối cùng: nếu bạn muốn kiểm tra, giả sử, tràn, bạn sẽ làm khác với số đã ký và số không dấu.


Ý bạn là gì bởi số chưa ký và số đã ký, điều tôi muốn hỏi là nếu tôi viết unsign int a = 2 và có chữ ký int b = 2, thì cả hai đều được ký hoặc không dấu, một số được ký hoặc không dấu phụ thuộc vào loại chúng ta gán nó cho, hoặc phụ thuộc vào việc nó có dấu âm hay không? Điều này đã được lỗi tôi cho một lúc.
Suraj Jain

@SurajJain đã kýchưa ký tham khảo các loại. Họ chỉ ra cho dù đó là tốt cho một biến hoặc biểu thức để có một giá trị âm.
Artelius

Tôi có nghi ngờ sau đây, tôi đã đặt câu hỏi, chưa có câu trả lời thỏa đáng nào, hãy xem nó ở đây, stackoverflow.com/questions/41399092/
Lỗi

62

Ông chỉ hỏi về việc ký và không dấu. Không biết tại sao mọi người lại thêm những thứ bổ sung vào đây. Hãy để tôi nói cho bạn câu trả lời.

  1. Chưa ký: Nó chỉ bao gồm các giá trị không âm tức là 0 đến 255.

  2. Đã ký: Nó bao gồm cả giá trị âm và dương nhưng ở các định dạng khác nhau như

    • 0 đến + 127
    • -1 đến -128

Và lời giải thích này là về hệ thống số 8 bit.


17

Chỉ cần một vài điểm cho sự hoàn chỉnh:

  • câu trả lời này chỉ thảo luận về các đại diện số nguyên. Có thể có câu trả lời khác cho điểm nổi;

  • đại diện của một số âm có thể thay đổi. Phổ biến nhất (cho đến nay - nó gần như phổ biến ngày nay) được sử dụng ngày nay là hai bổ sung . Các đại diện khác bao gồm phần bù của một người (khá hiếm) và cường độ đã ký (rất hiếm khi xảy ra - có lẽ chỉ được sử dụng trên các phần của bảo tàng) mà chỉ đơn giản là sử dụng bit cao làm chỉ báo ký hiệu với các bit còn lại biểu thị giá trị tuyệt đối của số.

  • Khi sử dụng phần bù của hai, biến có thể biểu thị một phạm vi lớn hơn (bằng một) số âm so với số dương. Điều này là do số 0 được bao gồm trong các số 'dương' (vì bit dấu không được đặt thành 0), nhưng không phải là số âm. Điều này có nghĩa là không thể biểu thị giá trị tuyệt đối của số âm nhỏ nhất.

  • khi sử dụng cường độ bổ sung hoặc ký hiệu của một người, bạn có thể có số 0 được biểu thị dưới dạng số dương hoặc số âm (đó là một trong một số lý do mà các đại diện này thường không được sử dụng).


Nếu tôi viết unsign int a = -2 và đã ký int b = -2, thì đại diện bên dưới có giống nhau không, tôi biết sẽ không tốt nếu có số không dấu được cho một giá trị âm, nhưng nếu tôi cho nó, thì nó sẽ là gì đại diện cơ bản?
Suraj Jain

1
Niggle nhỏ: dấu hiệu và cường độ được sử dụng trong điểm nổi của IEEE, vì vậy nó thực sự khá phổ biến. :-)
alastair

14

Theo những gì chúng ta đã học trong lớp, số nguyên đã ký có thể đại diện cho cả số dương số âm, trong khi số nguyên không dấu chỉ là số không âm.

Ví dụ: nhìn vào số 8 bit :

unsigned giá trị 0để255

ký kết các giá trị dao động từ -128để127


11

Tất cả mọi thứ trừ điểm 2 đều đúng. Có nhiều ký hiệu khác nhau cho các int đã ký, một số triển khai sử dụng cái đầu tiên, một số khác sử dụng cái cuối cùng và một số khác sử dụng cái gì đó hoàn toàn khác. Tất cả phụ thuộc vào nền tảng bạn đang làm việc.


Đó có phải là điều cuối cùng nhỏ và lớn cuối?
vIceBerg

ít so với endian lớn phải làm theo thứ tự của các byte trên nền tảng. Little endian có thể làm 0xFF 0xFE 0x7F trong khi endian lớn sẽ làm 0x7F 0xFE 0xFF.
Jasper Bekkers

10

Một sự khác biệt khác là khi bạn chuyển đổi giữa các số nguyên có kích thước khác nhau.

Ví dụ: nếu bạn trích xuất một số nguyên từ luồng byte (đơn giản là 16 bit), với các giá trị không dấu, bạn có thể thực hiện:

i = ((int) b[j]) << 8 | b[j+1]

(có lẽ nên truyền byte thứ 2 , nhưng tôi đoán trình biên dịch sẽ làm đúng)

Với các giá trị đã ký, bạn sẽ phải lo lắng về việc gia hạn ký và thực hiện:

i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF

5

Nói chung là đúng. Không biết gì thêm về lý do tại sao bạn đang tìm kiếm sự khác biệt, tôi không thể nghĩ ra bất kỳ sự khác biệt nào khác giữa ký và không dấu.


4

Hơn và hơn những gì người khác đã nói, trong C, bạn không thể tràn một số nguyên không dấu; hành vi được định nghĩa là số học mô đun. Bạn có thể tràn một số nguyên đã ký và theo lý thuyết (mặc dù không có trong thực tế trên các hệ thống chính hiện tại), tràn có thể gây ra lỗi (có thể tương tự như chia cho lỗi không).


1
Lưu ý rằng tràn số nguyên đã ký sẽ kích hoạt hành vi không xác định và các trình biên dịch hiện đại cực kỳ tích cực trong việc phát hiện ra điều này và khai thác nó để sửa đổi chương trình của bạn theo những cách bất ngờ nhưng hợp pháp về mặt kỹ thuật vì chúng được phép giả sử hành vi không xác định sẽ không xảy ra - nói một cách đại khái. Đây là một vấn đề nhiều hơn bây giờ so với 7 năm trước.
Jonathan Leffler

4
  1. Có, số nguyên không dấu có thể lưu trữ giá trị lớn.
  2. Không, có nhiều cách khác nhau để hiển thị giá trị tích cực và tiêu cực.
  3. Có, số nguyên đã ký có thể chứa cả giá trị dương và âm.

4

(để trả lời cho câu hỏi thứ hai) Chỉ bằng cách sử dụng một bit dấu (chứ không phải phần bù 2), bạn có thể kết thúc bằng -0. Không xinh lắm.


Chỉ cần thêm vào câu trả lời này, về cơ bản, điều đó có nghĩa là 10 == 00 trong đó cả hai số đó đều là cơ sở 2.

4

Số nguyên đã ký trong C đại diện cho số. Nếu ablà các biến của các kiểu số nguyên đã ký, tiêu chuẩn sẽ không bao giờ yêu cầu trình biên dịch biến biểu thức a+=blưu trữ thành abất cứ thứ gì ngoài tổng số học của các giá trị tương ứng của chúng. Để chắc chắn, nếu tổng số học không phù hợp a, bộ xử lý có thể không thể đặt nó ở đó, nhưng tiêu chuẩn sẽ không yêu cầu trình biên dịch cắt bớt hoặc bọc giá trị, hoặc làm bất cứ điều gì khác cho vấn đề đó nếu giá trị vượt quá các giới hạn cho các loại của họ. Lưu ý rằng mặc dù tiêu chuẩn không yêu cầu nó, nhưng việc triển khai C được phép bẫy các số tràn số học với các giá trị đã ký.

Các số nguyên không được gán trong C hoạt động như các vòng đại số trừu tượng của các số nguyên tương ứng với một số lũy thừa, ngoại trừ trong các trường hợp liên quan đến chuyển đổi hoặc hoạt động với các loại lớn hơn. Chuyển đổi một số nguyên kích thước bất kỳ thành loại không dấu 32 bit sẽ mang lại thành viên tương ứng với những thứ phù hợp với mod số nguyên đó là 4.294.967.296. Lý do trừ 3 từ 2 mang lại 4.294.967.295 là vì thêm một cái gì đó phù hợp với 3 vào một cái gì đó phù hợp với 4.294.967.295 sẽ mang lại một cái gì đó phù hợp với 2.

Các loại vòng đại số trừu tượng thường là những thứ tiện dụng cần có; Thật không may, C sử dụng chữ ký làm yếu tố quyết định cho việc một loại có nên hoạt động như một chiếc nhẫn hay không. Tệ hơn, các giá trị không dấu được coi là số thay vì thành viên vòng khi được chuyển đổi thành loại lớn hơn và giá trị không dấu nhỏ hơn intđược chuyển đổi thành số khi bất kỳ số học nào được thực hiện theo chúng. Nếu vlà một uint32_tmà bằng 4,294,967,294, sau đó v*=v;nên thực hiện v=4. Thật không may, nếu intlà 64 bit, thì không biết v*=v;phải làm gì.

Với tiêu chuẩn như hiện tại, tôi sẽ đề nghị sử dụng các loại không dấu trong các tình huống trong đó người ta muốn hành vi liên quan đến các vòng đại số và các loại được ký khi muốn đại diện cho các số. Thật không may khi C đã vẽ ra sự khác biệt theo cách nó đã làm, nhưng chúng là những gì chúng là.


3

Số nguyên không dấu có nhiều khả năng bắt bạn trong một cái bẫy cụ thể hơn nhiều so với số nguyên đã ký. Cái bẫy xuất phát từ thực tế là trong khi 1 & 3 ở trên là chính xác, cả hai loại số nguyên có thể được gán một giá trị bên ngoài giới hạn của những gì nó có thể "giữ" và nó sẽ được chuyển đổi âm thầm.

unsigned int ui = -1;
signed int si = -1;

if (ui < 0) {
    printf("unsigned < 0\n");
}
if (si < 0) {
    printf("signed < 0\n");
}
if (ui == si) {
    printf("%d == %d\n", ui, si);
    printf("%ud == %ud\n", ui, si);
}

Khi bạn chạy cái này, bạn sẽ nhận được đầu ra sau mặc dù cả hai giá trị được gán cho -1 và được khai báo khác nhau.

signed < 0
-1 == -1
4294967295d == 4294967295d

0

Sự khác biệt được bảo đảm duy nhất giữa giá trị được ký và giá trị không dấu trong C là giá trị đã ký có thể âm, 0 hoặc dương, trong khi giá trị không dấu chỉ có thể là 0 hoặc dương. Vấn đề là C không xác định định dạng của các loại (vì vậy bạn không biết rằng số nguyên của mình nằm trong hai phần bù). Nói đúng ra hai điểm đầu tiên bạn đề cập là không chính xác.


0

Bạn phải sử dụng Số nguyên không dấu khi lập trình trên Hệ thống nhúng. Trong các vòng lặp, khi không cần số nguyên đã ký, sử dụng số nguyên không dấu sẽ tiết kiệm an toàn cần thiết cho việc thiết kế các hệ thống như vậy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.