Tại sao máy tính đếm từ 0?


55

Máy tính truyền thống kiểm đếm các giá trị số bắt đầu từ số không. Ví dụ, các mảng trong các ngôn ngữ lập trình dựa trên C bắt đầu từ chỉ số 0.

Những lý do lịch sử nào tồn tại cho điều này, và những lợi thế thực tế nào khi đếm từ số 0 có so với việc đếm từ một?

Lưu ý: Câu hỏi này yêu cầu các câu trả lời kỹ thuật được giải thích rõ ràng, không chỉ là ý kiến ​​và nhằm mục đích bao quát các máy tính nói chung thay vì chỉ lập trình. Câu hỏi này mở rộng dựa trên câu hỏi của Lập trình viên "Tại sao cấu trúc / mảng không dựa trên?" .



9
Đã có nhiều hơn một vài ví dụ về ngôn ngữ máy tính sử dụng mảng 1 gốc.
Daniel R Hicks

23
Tại sao con người không đếm từ 0?
Chưa có tiêu đề

47
Woah, woah, không ai đếm từ số không, chúng tôi lập chỉ mục từ số không. Không ai nói yếu tố "zeroth". Chúng ta nói phần tử "đầu tiên" ở chỉ số 0. Hãy nghĩ về chỉ số như cách một phần tử được bù từ vị trí đầu tiên. Chà, phần tử đầu tiên ở vị trí đầu tiên, vì vậy nó hoàn toàn không bù trừ, vì vậy chỉ số của nó là 0. Phần tử thứ hai là một phần tử trước nó, vì vậy nó bù 1 phần tử và ở chỉ số 1
mowwwalker

14
@Ramhound Không, không phải vậy. Lập chỉ mục dựa trên zero hoàn toàn không liên quan đến việc sử dụng nhị phân.
Peter Olson

Câu trả lời:


88

Đếm các mảng từ 0 đơn giản hóa việc tính toán địa chỉ bộ nhớ của từng phần tử.

Nếu một mảng được lưu trữ tại một vị trí nhất định trong bộ nhớ (nó được gọi là địa chỉ), vị trí của mỗi phần tử có thể được tính là

element(n) = address + n * size_of_the_element

Nếu bạn coi phần tử đầu tiên là phần đầu tiên, tính toán sẽ trở thành

element(n) = address + (n-1) * size_of_the_element

Không phải là một sự khác biệt lớn nhưng nó thêm một phép trừ không cần thiết cho mỗi lần truy cập.

Biên tập

  • Việc sử dụng chỉ số mảng như một phần bù không phải là một yêu cầu mà chỉ là một thói quen. Phần bù của phần tử đầu tiên có thể được hệ thống ẩn và xem xét khi phân bổ và phần tử tham chiếu.

  • Dijkstra đã xuất bản một bài báo "Tại sao đánh số nên bắt đầu từ 0" ( pdf ) trong đó ông giải thích tại sao bắt đầu bằng 0 là lựa chọn tốt hơn. Bắt đầu từ 0 cho phép thể hiện phạm vi tốt hơn.


8
+1 cho câu trả lời đúng. Lưu ý rằng lập chỉ mục dựa trên 0 chỉ là quy ước (rất phổ biến) của ngôn ngữ đang được sử dụng; nó không phải là phổ quát. Chẳng hạn, Lua sử dụng lập chỉ mục dựa trên 1 . "Phép trừ không cần thiết" có thể là lý do đằng sau việc lập chỉ mục dựa trên 0 trong thời xưa, nhưng bây giờ hầu hết các ngôn ngữ sử dụng nó đơn giản vì đó là những gì mọi người đã quen (phần lớn là nhờ C) và không có lý do thuyết phục nào để thay đổi điều đó quy ước.
BlueRaja - Daniel Pflughoeft

2
Điều này không có ý nghĩa. Vị trí của mỗi phần tử luôn có thể được tính address + n * size_of_elementmiễn là "địa chỉ" là địa chỉ của phần tử zeroth. Điều này hoạt động hoàn hảo cho dù phần tử zeroth có tồn tại như một phần tử của mảng hay không. Câu hỏi là tại sao phần tử zeroth tồn tại, chứ không phải tại sao chúng ta lưu trữ địa chỉ làm địa chỉ của phần tử zeroth (có thể là đáng chú ý). (Câu trả lời này.)
David Schwartz

3
@DavidSchwartz Hãy lấy một ngôn ngữ là C. Nếu phân bổ bộ nhớ, bạn nhận được một địa chỉ nơi bộ nhớ bắt đầu. Nếu một trình biên dịch thấy một cái gì đó giống như v[n]nó phải tính địa chỉ của biểu thức. Nếu các chỉ mục bắt đầu bằng 0 thì tính toán có kích thước v + x *. Nếu tại 1 tính toán có kích thước v + (x-1) *. Ví dụ: v [1] sẽ tương ứng với kích thước v + (1-1) * đó là v.
Matteo

4
@David: Trong C (ngôn ngữ thực sự phổ biến lập chỉ mục dựa trên 0) , mảng và con trỏ phần lớn có thể hoán đổi cho nhau, vì vậy điều quan trọng là một số lý do *arraythực sự đề cập đến yếu tố đầu tiên. Một ví dụ: nếu chúng ta arraychỉ đến vị trí bộ nhớ trước phần tử đầu tiên, việc truyền tới một mảng thuộc loại khác sẽ gây rắc rối, ví dụ. vị trí của byte thứ hai trong một mảng ints sẽ trở nên phụ thuộc vào kích thước từ; trên máy 32 bit, nó sẽ ở ((char*)intArray + 5)!!
BlueRaja - Daniel Pflughoeft

3
Không, đây không phải là vấn đề liệu mảng có phần tử zeroth hay không. Bởi vì, bạn thấy, cũng có tỉ lệ. Nếu tôi có một mảng gồm 8 đối tượng byte và tôi che phủ nó bằng một mảng byte, chỉ số byte của đối tượng [42] là gì? Tại sao nó đơn giản: 42 * 8. Vấn đề với 1 dựa trên là phần bù 1 này là 1 byte khi tôi nhìn vào mảng byte và nó là 8 byte khi tôi nhìn vào mảng đơn vị 8 byte được phủ.
Kaz

38

Mặc dù các nguyên tắc dưới đây áp dụng cho thập phân cũng như bất kỳ cơ sở nào khác, Đếm từ 0 trong máy tính có thể dễ dàng hiểu một cách tự nhiên từ hệ thống nhị phân có chữ số cố định biểu thị các số được sử dụng trong máy tính. Nếu bạn có 8 bit, thì có 256 biểu thức kết hợp 1 và 0 có thể được biểu thị. Bạn có thể sử dụng 8 bit này để biểu thị các số 1-256, nhưng điều này sẽ bỏ qua 0 rất hữu ích trong toán học như là một số trong chính nó, vì vậy chúng được sử dụng để thể hiện các số 0-255.

Điều này đã đặt tiền lệ của một thứ tự tự nhiên bắt đầu từ 0 (tất cả 0 trong biểu diễn nhị phân) thành 255 (tất cả 1 trong một số 8 bit). Xem xét hệ thống biểu diễn các số, bắt đầu từ 0 có ý nghĩa vì 0 là số "đầu tiên" trong hệ thống, vì vậy 1 là số "thứ hai", v.v.

Một lý do bổ sung tại sao bắt đầu từ 0 trong máy tính rất thuận tiện là do khái niệm về độ lệch. Giá trị bù là một số biểu thị khoảng cách từ một vị trí trong bộ nhớ hoặc đĩa cứng hoặc bất kỳ phương tiện "địa chỉ" nào khác. Trong máy tính, thực tế tất cả dữ liệu được lưu trữ tuyến tính, nghĩa là có một thứ tự cho dữ liệu, một byte đầu tiên, một byte thứ hai, v.v ... Thật thuận tiện để thể hiện vị trí của "các khu vực" dữ liệu thông qua một phần bù. Byte đầu tiên trong một khối dữ liệu là gì? Nó ở độ lệch '0', có nghĩa là nó được tìm thấy 0 byte sau byte đầu tiên trong khối dữ liệu. Mặc dù có thể có "1" chỉ định byte đầu tiên, nhưng điều này tạo ra sự phức tạp trong việc biểu diễn dữ liệu vì một số lý do:

  • Bằng cách loại trừ 0 khỏi việc được sử dụng để xử lý dữ liệu, bạn giảm số lượng những thứ bạn có thể xử lý với số 8 bit một.
  • Để tính toán phần bù, cần thiết ở cấp độ phần cứng của truy cập dữ liệu, tại một số điểm, bạn phải trừ đi một phần khỏi việc đánh số, điều này dẫn đến sự phức tạp.
  • Con trỏ tới một khối dữ liệu luôn trỏ đến khối đầu tiên, vì vậy số học rất đơn giản khi bạn bắt đầu từ 0. (nghĩa là byte thứ 1 trong khối đầu tiên của cụm dữ liệu đầu tiên là 0 + 0 + 0 khi bạn bắt đầu từ 0 , đó là 1 + 1 + 1 - 1 -1 khi bạn bắt đầu từ 1.) Số học cho điều này khi bạn bắt đầu từ 1 với các cơ sở dữ liệu lồng nhau như ví dụ này có thể gây nhầm lẫn.

31
Không có gì để làm với đại diện nhị phân. Cả hai số nhị phân và số thập phân bắt đầu từ 0.
Matteo

2
Nếu bạn bắt đầu đếm từ 0, bạn không giảm số lượng địa chỉ bạn có thể (về lý thuyết) đi từ 1 xuống còn 257.
Matteo

6
@Matteo không phải trong một byte mà bạn không thể
Ngừng làm hại Monica

8
@Dougvj Tính không dựa hoàn toàn không liên quan gì đến nhị phân. Điểm bạn đang thực hiện là về việc sử dụng mọi số trong biểu diễn chữ số cố định, đây là mối quan tâm bất kể bạn đang sử dụng cơ sở 2, cơ sở 10 hay cơ sở 23517.
Peter Olson

2
-1 Nó hoàn toàn không có gì để làm với biểu diễn nhị phân.
BlueRaja - Daniel Pflughoeft

26

Không bao giờ nghĩ rằng một cơ hội cho một triết gia ghế bành như tôi sẽ đến với Superuser. Có một quan niệm sai lầm cơ bản ở đây, bởi vì những người không phải là triết gia có xu hướng bỏ qua các chi tiết nhỏ. Tóm lại: Máy tính không được tính từ 0, nhưng mệnh giá của các vị trí bắt đầu từ 0.

Không có gì khó hiểu về sự không thống nhất nhận thức này giữa máy tính và kỹ thuật đếm của con người (bất kỳ). Hãy phân tích câu hỏi.

Tại sao máy tính đếm từ 0?

  • Họ không tính từ số không

Giá trị kiểm đếm máy tính bắt đầu từ số không. Ví dụ, mảng trong C.

  • Các chỉ số (chỉ số về vị trí, kiểm đếm) bắt đầu từ con số không. Tổng số phần tử trong một mảng trong đó có một phần tử duy nhất ở chỉ số 0 là một phần tử

Không là thực tế để đại diện cho một khoảng trống của một cái gì đó hoặc điểm giữa của một quy mô. Nó không thực tế để đếm bất cứ điều gì vì không thể định nghĩa bằng không.

Theo nghĩa tương tự như điểm giữa của một thang đo, số 0 có thể được sử dụng để thể hiện chính cạnh (bắt đầu tuyệt đối) của một bộ sưu tập. Câu hỏi là vô nghĩa vì nó không nhất quán giữa "giá trị kiểm đếm" và "đếm từ 0".

Vì vậy, có, máy tính kiểm đếm từ số không, nhưng chúng đếm từ một. Hai từ mang ý nghĩa khác nhau.

tài năng [ Tal -ee]

danh từ

  1. một tài khoản hoặc tính toán; một bản ghi nợ và tín dụng, về điểm số của một trò chơi, hoặc tương tự.
  2. bất cứ điều gì mà điểm số hoặc tài khoản được lưu giữ ..
  3. một số hoặc nhóm các mặt hàng được ghi lại.

đếm [kount]

động từ (được sử dụng với đối tượng)

  1. để kiểm tra (các đơn vị hoặc nhóm riêng biệt của một bộ sưu tập) từng cái một để xác định tổng số; thêm vào; liệt kê: Anh ta đếm vé và thấy anh ta có mười.
  2. để tính toán lên; tính toán; tính toán
  3. để liệt kê hoặc đặt tên cho các chữ số lên đến: Nhắm mắt và đếm mười.

(từ điển.com)


Những lý do thực tế được Dougvj mô tả đầy đủ, tôi không có gì để thêm vào đó. Giá như chúng ta có thể có một giáo sư CS (từ thập niên 60) đưa ra một tài khoản lịch sử ...


Trong thực tế, làm thế nào để bạn biết máy tính bắt đầu từ đâu? Tất cả những gì bạn biết là, khi bạn sử dụng nó, bạn NÓI nó để bắt đầu từ con số không.
Daniel R Hicks

Tôi đang nói về định nghĩa của các khái niệm và logic ở đây, không phải là cách máy tính hoạt động. Tôi biết một chút về nơi máy tính bắt đầu mọi thứ vì tôi đã tham gia các khóa học CS.
Ярослав Рахматуллин

1
Để hoàn toàn mô phạm, bạn đang so sánh một động từ với một danh từ. Tôi nghĩ "tally" và "Count" thực sự là đồng nghĩa và cả hai có thể được sử dụng như một động từ hoặc danh từ.
Brian

1
@Brian Một quan sát công bằng và ý định của tôi là để minh họa (theo cách mô phạm) rằng sự nhầm lẫn bắt nguồn từ việc giải thích sai các thuật ngữ. Thực sự không có sự khác biệt giữa "phần tử thứ 1" và "phần tử ở vị trí 0". Cả hai đều là yếu tố một. Đầu tiên , không phải " zeroth ". Không có gì gọi là đếm từ số không . Việc liệt kê bắt đầu từ một định nghĩa, trong khi địa chỉ có thể là a-> 1, b-> 2. c-> 3 hoặc 0-> 1, 1-> 2, 2-> 3. Ví dụ phổ biến nhất về "đếm từ 0" có thể được tìm thấy trong các sách toán ở trường trung học dưới dạng {x₀, x₁, x₂} - nhưng chỉ số là một chỉ mục .

1
Chỉ là các nhà thiết kế thực sự đã đi lang thang xung quanh khá nhiều trước khi họ giải quyết chương trình hiện tại. Những gì có vẻ "rõ ràng" bây giờ không phải là. Và có khả năng một sơ đồ hơi khác có thể đã được chọn và bây giờ có vẻ "rõ ràng" hơn những gì chúng ta có.
Daniel R Hicks

12

Tôi nghĩ rằng điều này đã được đề cập trước đây bởi " prof.dr. Edsger W. Dijkstra " - Nghiên cứu viên của Burroughs trong một lá thư ngày 11 tháng 8 năm 1982: cf EWD831

Tiêu đề: Tại sao đánh số nên bắt đầu từ số không . "Có lý do nào để thích một quy ước khác không? Có, có ...."

Cũng lưu ý rằng Dijkstra thuộc nhóm thiết kế ALGOL 68 vào cuối năm 1968. Algol68 cho phép các mảng từ 0, 1 hoặc bất kỳ số nào mà lập trình viên thấy phù hợp với thuật toán. cf ( "The Making of Algol 68" kể lại 'Bạn có thể định nghĩa các mảng hình tam giác không? Một ai đó (Tony Hoare?) đã ngắt lời. Không chỉ là hình tam giác, mà ngay cả hình elip đã trả lời Aad, và chỉ ra cách nào.')

Cụ thể, trong Algol68, khi các mảng (& ma trận) được cắt lát, chúng nhận được một chỉ số @ 1, do đó có sự thiên vị đối với các mảng [1: ...]. Tuy nhiên, "1 st " thấp hơn giới hạn có thể được di chuyển để bắt đầu tại "0 thứ " vị trí bằng cách xác định "@ 0", ví dụ như vector x [4: 99 @ 2], ma trận y [4: 99 @ 1,4: 99 @ 0]. Tương tự, có một mặc định / độ lệch từ 1 trong các vòng lặp do ~ od (trừ khi " từ 0" được nêu rõ ràng) và từ 1 cho trường hợp số nguyên i trong ~, ~, ~ esac và $ c (~, ~, ~ ) mệnh đề lựa chọn $ .

Dường như ý kiến của Dijkstra về tháng 3 năm 1968 Dự thảo Báo cáo ( MR93 ) và insistences mình gây những gì được cho là một pre-usenet ngọn lửa chiến tranh : "có những tác phẩm mà là đáng yêu mặc dù việc sai ngữ pháp, và có tác phẩm khác đó là cực kỳ ngữ pháp, nhưng là kinh tởm. Đây là điều mà tôi không thể giải thích cho những người hời hợt. " EWD230

Báo cáo cuối cùng của Algol 68 (FR) ra đời vào ngày 20 tháng 12 năm 1968 khi nó được bực bội tại Hội nghị Munich và sau đó được Nhóm công tác thông qua. Sau đó, báo cáo được chấp thuận bởi IFIP của Đại hội đồng UNESCO để xuất bản.

Khoảng 23 tháng 12 (?) 1968 Dijkstra, Duncan, Garwick, Hoare , Randell , Seegmuller, Turski, Woodger và Garwick ký AB31.1.1.1 "Minority Report", trang 7 (Published 1970).


10

Sự tương tự về khoảng cách mà người khác đưa ra cho thấy một minh họa rất thực tế:

"Nhà bạn cách trạm xăng gần nhất bao xa?"

"1 dặm."

"Bạn sống ở trạm xăng?"

"Không, nếu tôi sống tại các trạm xăng nó sẽ là 0 dặm"

"Tại sao bạn đếm từ 0 thay vì từ một?"

Một ví dụ điển hình khác sẽ là sinh nhật - chúng ta không nói ai đó tròn một tuổi vào ngày họ được sinh ra, chúng ta nói đó là một năm sau đó.

Chúng tôi nói rằng năm nhuận hoặc cuộc bầu cử tổng thống Mỹ cứ bốn năm một lần, mặc dù nếu bạn tính từ một: 2000 , 2001, 2002, 2003, 2004 là năm năm. (Ngẫu nhiên, người La Mã đã làm hỏng việc này một thời gian và có những năm nhuận quá gần nhau)

Quan điểm của tôi là, chúng tôi "đếm" từ số 0 mọi lúc trong thế giới thực - "Có bao nhiêu vị trí sau [bắt đầu mảng] là yếu tố bạn muốn" chỉ đơn giản là câu hỏi bạn đang trả lời với số đếm từ 0 trong nhiều chương trình máy tính. Bạn sẽ không nói rằng yếu tố đầu tiên là một vị trí sau khi bắt đầu, phải không? Đó sự khởi đầu.


1
Toán học của bạn liên quan đến cuộc bầu cử đã hết một năm. Ví dụ của bạn có 2 năm bầu cử trong vòng 5 năm; minh họa chính xác là 4 năm trôi qua từ cuộc bầu cử này sang cuộc bầu cử tiếp theo, tức là 2000 -> 2001 (khoảng thời gian 1 năm), 2001 -> 2002, 2002 -> 2003, 2003 -> 2004.
Jimmy

1
@Jimmy Đó là quan điểm của tôi - nếu mọi người "đếm từ một" theo nghĩa họ muốn máy tính, họ sẽ tính 2000 là một thay vì bằng không. Đây là, tình cờ, người La Mã cổ đại thực sự đã làm điều đó như thế nào (và thực sự sẽ mô tả một chu kỳ như "2000, 2004, 2008" là một chu kỳ năm năm).
Random832

2
Ví dụ sinh nhật của bạn không phải là phổ biến đúng. Ví dụ, ở Hàn Quốc năm đầu tiên của cuộc đời được tính là một thay vì bằng không .
BennyMcBenBen

6

Như đã nói bởi những người khác máy tính không được tính từ số không .

Một số ngôn ngữ lập chỉ mục từ 0. Lập chỉ mục từ 0 có hai ưu điểm chính:

  1. Nó chuyển đổi để lắp ráp theo cách tự nhiên bởi vì nó có thể được hiểu là một phần bù từ một con trỏ đến vị trí đầu tiên.

  2. Bạn không nhận được sự kỳ lạ khi bạn muốn tiêu cực. Bao nhiêu năm giữa 1BC và 1AD? Không ai. Bởi vì mặc dù BC là ngày âm thực sự, không có năm nào. Nếu có 0AD thì sẽ không có vấn đề gì ở đây cả. Bạn thấy vấn đề tương tự ở khắp mọi nơi trong khoa học nơi mọi người đã xác định một cách ngây thơ yếu tố đầu tiên trong một tập hợp là +1.


Vâng, và toàn bộ sự ngu ngốc của việc chờ đợi cho đến năm 2001 cho thiên niên kỷ mới. Điều này gây nhầm lẫn chính xác cho những người cũng không "có được" các mảng dựa trên zero khi họ học lập trình. :)
Kaz

3
Ngoài ra, nếu "1 dặm" ​​có nghĩa là "ngay tại đây", thì vì một dặm là 1760 feet, có nghĩa là "1760 feet" cũng có nghĩa là "ngay tại đây", phải không? Sai, "1 chân" có nghĩa là ngay tại đây, rất tiếc! Trong sự ngu ngốc dựa trên một điều này, "ngay tại đây" là một chân, một inch, một centimet, v.v.
Kaz

1
@kaz nơi chân => sân. 1760 yard trong một dặm.
Brad

3

Đếm tự nhiên bắt đầu từ 0

Đây là thuật toán đếm táo trong một giỏ:

count := 0

for each apple in basket
   count := count + 1

Sau khi thực hiện ở trên, countgiữ số táo. Nó có thể bằng 0, vì giỏ có thể trống.

Nếu bạn không sử dụng thẻ tín dụng trong cả tháng, bạn có nhận được hóa đơn 1 đô la không? Hay 1 xu?

Khi bạn đặt lại đồng hồ đo hành trình trên đồng hồ đo của xe, nó sẽ chuyển sang 0001 hoặc 0000?

Mảng có thể cung cấp nhiều chế độ xem của cùng một dữ liệu

Hãy xem xét một mảng gồm các cấu trúc 32 bit d, mỗi cấu trúc được tạo từ 16 bit w. Mỗi từ được tạo thành từ hai byte 8 bit b. Trong chỉ mục không, lớp phủ trông rất thuận tiện:

d: |   0   |   1   |
w: | 0 | 1 | 2 | 3 |
b: |0|1|2|3|4|5|6|7|

Đối tượng 32 bit d[1]như tại địa chỉ từ w[2]có thể dễ dàng tính toán bằng cách nhân chỉ số với 2, tỷ lệ kích thước của đối tượng 32 và 16 bit. Hơn nữa, trong địa chỉ byte, nó là b[4].

Điều này hoạt động vì số không bằng 0, trong mọi đơn vị đo lường: byte, từ, từ kép, v.v.

Nhìn vào sơ đồ trên: nó trông giống như một cây thước, trong đó các chuyển đổi đơn vị là trực quan.

Với một chỉ mục dựa trên, nó phá vỡ:

d: |   1   |   2   |
w: | 1 | 2 | 3 | 4 |
b: |1|2|3|4|5|6|7|8|

Bây giờ chúng ta không thể đơn giản nhân dchỉ số với 2 để lấy wchỉ mục hoặc 4 để lấy bchỉ mục. Việc chuyển đổi giữa các đơn vị trở nên vụng về. Ví dụ để đi từ d[2]đến b[4], chúng ta phải tính toán ((2 - 1) * 4) + 1 = 5.

Chúng ta phải loại trừ độ lệch 1 pesky trong các dđơn vị, sau đó thực hiện chia tỷ lệ trong hệ tọa độ dựa trên số 0 tự nhiên, sau đó thêm lại pesky 1 theo bđơn vị. Lưu ý rằng nó không giống nhau 1! Chúng tôi trừ đi một chiều rộng từ kép, nhưng sau đó thêm vào một chiều rộng byte .

Chuyển đổi giữa các chế độ xem khác nhau của dữ liệu trở thành một cái gì đó giống như chuyển đổi Celsius-Fahrenheit.

Những người nói rằng các mảng dựa trên một cách dễ dàng để xử lý ở cấp độ thực hiện, bởi vì chỉ có một phép trừ đơn giản là 1 đang tự lừa mình và bạn. Điều này chỉ đúng nếu chúng tôi không thực hiện bất kỳ tính toán tỷ lệ nào giữa các loại dữ liệu khác nhau. Các tính toán như vậy xảy ra trong bất kỳ chương trình nào có chế độ xem linh hoạt về dữ liệu (ví dụ: mảng đa chiều cũng được truy cập dưới dạng một chiều) hoặc thao tác lưu trữ: ví dụ: bộ cấp phát bộ nhớ, hệ thống tệp hoặc thư viện bộ đệm khung video.

Thu nhỏ chữ số

Trong bất kỳ cơ sở nào, nếu chúng ta muốn sử dụng một vài chữ số nhỏ nhất để thực hiện một phạm vi các giá trị là sức mạnh của cơ sở, chúng ta phải bắt đầu từ số không. Chẳng hạn, trong cơ sở mười, ba chữ số là đủ để cung cấp cho chúng tôi một nghìn giá trị riêng biệt từ 0 đến 999. Nếu chúng tôi bắt đầu từ 1, chúng tôi sẽ tràn qua chỉ một giá trị và chúng tôi cần bốn chữ số.

Điều này rất quan trọng trong máy tính, vì số chữ số trong nhị phân chuyển thành các dòng địa chỉ phần cứng. Ví dụ, một chip ROM có 256 từ trong đó có thể được xử lý từ 0 đến 255, yêu cầu 8 bit: 00000000 đến 11111111. Nếu nó được xử lý từ 1 đến 256, thì cần chín bit. Chúng ta phải lãng phí thêm một dấu vết địa chỉ vào bảng mạch hoặc mạch tích hợp. Vì vậy, những gì có thể xảy ra trong thực tế sẽ là 0 sẽ được gọi1 ở cấp API phần mềm để truy cập chip đó. Một yêu cầu cho từ 1 thực sự sẽ đặt 00000000 trên bus địa chỉ 8 bit. Hoặc nếu không, một yêu cầu trong vòng 1 sẽ dịch để giải quyết 00000001, như mong đợi, nhưng yêu cầu 256 sẽ ánh xạ các trường hợp không sử dụng địa chỉ 8 bit 00000000 chứ không phải là 9 bit địa chỉ 100000000. Cả hai kludges túi cắn là thực sự giải pháp trong tìm kiếm một vấn đề và được tránh hoàn toàn bằng cách sử dụng nhất quán 0 đến 255 tại phần cứng, trong phần mềm và trong tất cả các giao diện và tài liệu người dùng.

Chuyển vị một chiều về cơ bản là ngu ngốc

Hãy xem xét lý thuyết âm nhạc phương Tây chẳng hạn. Chúng tôi có thang đo diatonic với bảy nốt nhạc, nhưng chúng tôi gọi không gian mà chúng bao phủ một quãng tám ! Đảo ngược các khoảng sau đó tuân theo quy tắc chín : ví dụ đảo ngược của một phần ba là một phần sáu (trừ ba từ chín). Vì vậy, ba số khác nhau đang chơi cho một cái gì đó rất đơn giản: bảy (ghi chú theo tỷ lệ), tám (quãng tám) và chín (trừ từ đảo ngược).

Nếu bảy nốt nhạc tạo thành một vách ngăn hoặc vách ngăn, và các khoảng không dựa trên, thì chúng ta sẽ trừ đi từ bảy đến đảo ngược. Tất cả mọi thứ dựa trên bảy.

Hơn nữa, các khoảng có thể dễ dàng xếp chồng lên nhau. Trong hệ thống hiện tại, nếu chúng ta nhảy một phần năm và sau đó một phần tư một lần nữa, và sau đó một phần ba, chúng ta không thể chỉ thêm những thứ này. Khoảng kết quả là hai ít hơn. Nó không phải là một phần mười, nhưng thực sự là một phần mười! Ở mỗi giai đoạn, chúng ta phải trừ đi một. Đi lên một phần năm và sau đó một phần tư không phải là một phần chín, mà chỉ là một quãng tám.

Trong một hệ thống âm nhạc được thiết kế hoàn hảo, chúng tôi chỉ có thể thêm các quãng để xác định các bước nhảy kết quả. Một chuỗi các ghi chú bắt đầu và kết thúc trên cùng một ghi chú sau đó sẽ có một tính chất tương tự như định luật điện áp xung quanh một mạch: tất cả các khoảng sẽ thêm vào không.

Lý thuyết âm nhạc và văn bản đã lỗi thời. Hầu hết nó đã không thay đổi kể từ ngày sáng tác được thực hiện bằng bút lông bằng ánh sáng của một ngọn nến.

Các hệ thống một nền tảng gây nhầm lẫn cho cùng những người không thể xử lý các mảng dựa trên zero

Khi năm 2000 trôi qua, nhiều người đã nhầm lẫn tại sao thiên niên kỷ mới chưa bắt đầu. Những người chỉ ra rằng nó sẽ không bắt đầu cho đến năm 2001 được coi là kẻ săn trộm của đảng và kẻ lừa đảo. Rốt cuộc, bạn ở độ tuổi 20 khi bạn 20 tuổi, phải không? Không phải khi bạn bước sang tuổi 21. Nếu bạn nghĩ rằng thiên niên kỷ bắt đầu vào ngày 1 tháng 1 năm 2000, thì bạn không có quyền phàn nàn về mảng dựa trên số 0 trong bất kỳ ngôn ngữ lập trình nào. Họ làm việc như thế nào chính xác như thế nào bạn thích. .

Lịch là câm, nhưng ít nhất thời gian trong ngày là không dựa trên

Mỗi phút mới trên đồng hồ của bạn bắt đầu bằng: 00 giây. Mỗi giờ mới bắt đầu với 00:00 phút và giây. Và, ít nhất là trên đồng hồ 24 giờ, ngày trôi qua khi nửa đêm đình công và 11:59:59 tăng lên 00:00:00.

Do đó, nếu bạn muốn tính toán giây từ nửa đêm trong khoảng thời gian như 13:53:04, bạn chỉ cần đánh giá 13 * 3600 + 53 * 60 + 4. Không có 1bổ sung hoặc trừ.

Kết thúc bài hát về MIDI

Được rồi, nó là gì với các nhạc sĩ, thậm chí được cho là kỹ thuật?

MIDI! Nó sử dụng đánh số dựa trên số không cho các chương trình và kênh trong biểu diễn dây thực tế của tin nhắn, nhưng thiết bị hiển thị dưới dạng 1 dựa trên! Ví dụ, các chương trình 0 đến 127 được gọi là 1 đến 128 trên hầu hết các thiết bị, nhưng một số gọi chúng là 0 đến 127 hoặc thậm chí cho người dùng lựa chọn.

Các chương trình 71 đến 80 được coi là một "ngân hàng" gồm mười. Nó nói như vậy ngay trên bàn đạp MIDI của tôi, ví dụ. Các footswitch được dán nhãn từ 1 đến 10 và nếu tôi ở ngân hàng thứ bảy, họ chọn các chương trình 71 đến 80. Tuy nhiên, một số thiết bị hoặc phần mềm máy tính hiển thị các số chương trình 1-128 là 0 đến 127 hoặc thậm chí cung cấp cho người dùng sự lựa chọn Điều gì tồi tệ hơn: các hệ thống dựa trên một, hoặc hỗn loạn được tạo ra bằng cách sử dụng cả một và không dựa trên cùng một lúc?

Số kênh MIDI được gọi là 1 đến 16, nhưng được biểu thị bằng 0 đến 15 nhị phân. Như thể không phù hợp với bản trình bày một lần, một số thiết bị sử dụng một nút tách rời để định cấu hình số kênh và thông thường, các công tắc chỉ sử dụng mã nhị phân dựa trên số không. Vì vậy, nếu bạn muốn kênh 3, bạn phải chuyển nó sang 0010 (nhị phân 2).


1

Nếu tôi nhớ lại chính xác từ lớp Khái niệm ngôn ngữ lập trình của tôi ... các ngôn ngữ được lập chỉ mục 0 và các ngôn ngữ khác là 1 chỉ mục phải làm với lý do lịch sử. Algol-68, cha đẻ của các ngôn ngữ lập trình thực sự là 1 chỉ mục, cũng như Fortran và một vài ngôn ngữ "kinh doanh" khác như COBOL. Tuy nhiên, trong một số ngôn ngữ này, bạn thực sự có thể chỉ định rõ ràng chỉ số bắt đầu của bạn sẽ là gì. Có một bảng thú vị về điều này ở đây .

Về cơ bản trở lại trong " Ye Olde ngày " nhà toán học, nhà khoa học, và "học giả" khác thường được sử dụng 0-lập chỉ mục ngôn ngữ, trong khi những người sử dụng ngôn ngữ như COBOL tìm thấy nó không sử dụng để bắt đầu đếm từ 0, vì vậy trong những ngôn ngữ đó có ý nghĩa hơn để bắt đầu từ 1 (có vẻ ít khó hiểu hơn).

Bây giờ nếu câu hỏi của bạn đề cập đến lý do tại sao một máy tính ( không phải ngôn ngữ ) tự nhiên bắt đầu đếm từ 0 ... thì tôi đoán là vốn có trong nhị phân thực sự: ex: 0000= zero 0001= one ... vân vân và vân vân ra ...


4
Không có gì để làm với đại diện nhị phân. Cả số nhị phân và số thập phân bắt đầu từ 0 (như bạn thể hiện trong ví dụ của mình).
Matteo

Vâng, nó có một cái gì đó khác để làm với nhị phân. Với bốn bit, 0000 đến 1111, bạn có thể giải quyết một ngân hàng bộ nhớ gồm 16 từ. Nếu bạn làm điều đó một lần, thì bạn cần năm dòng địa chỉ để biểu thị 0001 đến 10000. Hoặc nếu không, bạn sẽ làm gì với MIDI với số kênh: 0000 được sử dụng nội bộ, nhưng giao diện người dùng hiển thị 1! Nếu phần cứng dựa trên thập phân, thì đó cũng là vấn đề tương tự. Ba chữ số cung cấp cho bạn một nghìn địa chỉ nếu bạn bắt đầu từ số 0, nhưng nếu bạn bắt đầu từ 1, bạn cần bốn chữ số.
Kaz

1

Số 0 có thể biểu thị ý nghĩa khác nhau: giá trị số, thứ tự, địa chỉ bộ nhớ, v.v.

'Index zero' không có nghĩa là lập trình viên đếm từ 0. Nó biểu thị vị trí đầu tiên của khối bộ nhớ được phân bổ và '0' là địa chỉ của khối.

Trong C, việc lặp qua một mảng có thể được viết như dưới đây:

int arr[N];
for (i=0; arr[N]; ++i) {
...
}

Công việc tương tự có thể được thực hiện trong C #:

Object[] arr;

for (Object o in arr) {
...
}

Tôi nghĩ rằng không có tính trong cả hai ví dụ.


1

Bắt đầu từ 0 là thực tế khi mô tả một khoảng cách từ một cái gì đó. Vì vậy, trong mảng này:

[4,9,25,49]

khoảng cách từ điểm bắt đầu của mảng đến 25 là 2 - bạn cần bỏ qua hai bước để đến đó. Khoảng cách đến 4 là 0 - bạn không cần phải di chuyển từ đầu.

Thật là thực tế khi nghĩ như thế này khi thêm khoảng cách (hoặc chỉ mục) - Tôi tiến lên một bước, rồi bước không, rồi hai bước, tôi đang ở đâu? Tôi đang ở chỉ số 1 + 0 + 2 = 3. Bỏ qua ba bước, tôi kết thúc ở 49 trong mảng trên.


Đếm các tầng trong một tòa nhà thực sự phải giống như vậy (mặc dù chúng tôi không làm theo cách đó ở Hoa Kỳ) Tầng trệt nên bằng 0 vì bạn không đi lên hoặc xuống; đó là một vị trí bắt đầu.

Tuy nhiên, tầng trệt là nơi đầu tiên bạn đến. Bạn bắt đầu đếm khi bạn vào tòa nhà, ở tầng trệt và thêm khi bạn đi lên. Bắt đầu từ con số 0 có ý nghĩa nếu bạn coi "trong một tòa nhà" là trạng thái mặc định / bình thường / tự nhiên, đó là lời bình luận thú vị về xã hội đô thị. Không đối với mặt đất cũng có nhiều ý nghĩa nếu nhiều cấp độ phụ là phổ biến.

1

Hãy nhớ cách các con số được thể hiện trong một máy tính. Hãy lấy một bytebiến. 0 được biểu diễn dưới dạng 00000000 1 ở dạng nhị phân. 1 là 00000001. 2 là 00000010. vân vân.

Lưu ý rằng số thấp nhất mà a bytecó thể lưu trữ là 0. Nếu chúng ta bắt đầu các chỉ số mảng bằng 1, thì hệ thống sẽ không hiệu quả, vì bây giờ chúng ta có một mảng có độ dài 255 thay vì 256. Vì các số trong chương trình C biên dịch thành số nhị phân ( intthông thường, unsigned ints trong các chỉ số mảng), có vẻ tự nhiên khi sử dụng 0 làm chỉ số bắt đầu vì nó hiệu quả hơn.

Ngoài ra, trong C ++, a[p]mở ra *(a+p*n), nkích thước của kiểu dữ liệu ở đâu. Nói cách khác, a[p]có nghĩa là "Hãy cho tôi yếu tố tại chỉ mục a+n*p". Nếu pbắt đầu bằng 1, thì chúng tôi sẽ có một phần trống / không sử dụng tại chỉ mục a.

1. Tất nhiên, câu hỏi rõ ràng "tại sao" phát sinh. Tại sao không đặt 00000000 to1? Đơn giản: phép cộng nhị phân (được thực hiện bằng các tầng của đơn vị bộ cộng đầy đủ) dễ dàng trong phần cứng khi 00000000 bằng 0. Phép cộng nhị phân là một phần không thể thiếu của tất cả các phép toán số học. Nếu bạn làm cho nó đại diện cho 1, bạn cần phải yêu cầu trình biên dịch trừ 1 khỏi tất cả các số hoặc bạn cần phải cứng cáp các mạch cộng để trừ một đầu tiên khỏi các số cộng và giải mã lại cho tổng. (lưu ý rằng bạn không thể trừ đi một lần sau, vì bit carry có thể được tham gia)


@sec vì điều đó trở nên vô lý ở cấp độ phần cứng (xem chỉnh sửa)
Manishearth

1

Modulo

Một điều mà các câu trả lời tốt hiện tại chưa đề cập đến: lập chỉ mục dựa trên zero hoạt động tốt cùng với các phép toán modulo, do đó có thể được kết hợp để tạo thành danh sách tuần hoàn. Hãy suy nghĩ ví dụ về một cái gì đó như

color = colors[i % colors.length]

có thể cung cấp cho mỗi đối tượng (được lập chỉ mục bởi i) một màu khác nhau từ danh sách colors, cho đến khi tất cả các màu đã được sử dụng, tại thời điểm đó, nó sẽ bắt đầu lại từ đầu. Thể hiện tương tự trong lập chỉ mục một dựa trên là khá vụng về:

color = colors[(i - 1) % colors.length + 1]

Các hoạt động modulo tự động được áp đặt bởi số học nhị phân không dấu có kích thước cố định với bao quanh là một ví dụ khác về lý do tại sao điều này có ý nghĩa.

Phục vụ cho cả hai

Một điều khác cần xem xét là thực tế là khá dễ dàng để không sử dụng phần tử đầu tiên của mảng dựa trên zero. (Điều này không giữ cho foreachlặp kiểu và cấu trúc ngôn ngữ tương tự mà đối xử với các mảng như một toàn thể.) Nhiều lập trình viên, trong đó có tôi, có thể cảm thấy một chút vụng về không gian lãng phí, nhưng trong hầu hết các tình huống số tiền rất nhỏ rằng những lo lắng là vô căn cứ. Mặt khác, nếu các ngôn ngữ đang sử dụng lập chỉ mục dựa trên một, thì không có cách nào để mô phỏng một phần tử ở chỉ số 0 mà không có nhiều mã. Vì vậy, trong một số trường hợp, lập chỉ mục dựa trên số 0 tốt hơn so với dựa trên một, chọn số 0 làm cơ sở ở mọi nơi là cách tiếp cận linh hoạt hơn, trái ngược với một nền tảng ở mọi nơi và nó cũng phù hợp hơn so với các vị trí bắt đầu có thể định cấu hình.


0

Hệ thống máy tính sử dụng cả số tự nhiên (đếm từ 0) và toàn bộ số (tính từ 1). Mọi người đếm số thứ trong toàn bộ số, điều này làm cho chúng trực quan để đánh số danh sách và nhiều ngôn ngữ lập trình tận dụng lợi thế đó: BASIC, COBOL, Fortran, Lua và Pascal đều được tính từ 1. Các ngôn ngữ này nhắm vào các hốc như xử lý dữ liệu, phân tích số, và giảng dạy, trong đó danh sách đơn giản, trực quan là một lợi thế.

Toàn bộ số trở nên khó xử khi bạn bắt đầu phân tích và thao tác cấu trúc dữ liệu, thay vì chỉ xử lý mọi thứ theo thứ tự. Khi bạn cần tham khảo các chuỗi trong một công thức hoặc thuật toán, việc đánh số chúng từ 0 sẽ dễ dàng và ít bị lỗi hơn, như các nhà toán học thường làm: 0 , 1 , n , v.v. Nếu không, bạn thường phải điều chỉnh bằng +1 và C11 để có được dữ liệu phù hợp và rất dễ mắc lỗi, tạo ra lỗi. Do đó, các ngôn ngữ được thiết kế cho các nhà khoa học máy tính thường sử dụng các số tự nhiên: C, Java và Lisp đều được tính từ 0.

Ngoài ngôn ngữ lập trình, rất nhiều hệ thống máy tính đánh số thứ từ 0 vì đó là những gì các nhà khoa học máy tính đã quen. Ngoài ra, vì đánh số từ 1 dẫn đến rất nhiều lỗi ngấm ngầm, nhiều người trong chúng ta tránh nó bên ngoài các yếu tố giao diện được thiết kế nghiêm ngặt cho người dùng cuối không có kỹ thuật.


Java ... cho các nhà khoa học máy tính. CƯỜI NGẢ NGHIÊNG!
Kaz

0

Câu trả lời đơn giản là chữ số đầu tiên không phải là 1 mà là 0.

Giải thích: Công thức tính một số có nhiều chữ số trong bất kỳ cơ sở nào là:

n = sum(i=0 to n, Di^i)

WHERE 
n = numeric result
i = index (starting with 0)
Di = is the digit at index i

Chúng ta hãy lấy hệ thống thập phân, đó là hệ thống chúng ta quen thuộc nhất.

Nhìn vào số 1234, chúng ta có thể viết nó là:

4 x 10^0 = 4
3 x 10^1 = 30
2 x 10^2 = 200
1 x 10^3 = 1000

in other words, sum of digits raised to the power if their index.

Vì vậy, nó không chỉ là máy tính, chúng tôi, mọi người, cũng được tính từ 0.


0

Một chỉ mục mảng là phần bù từ vị trí bộ nhớ cơ sở đến vị trí bộ nhớ của phần tử. Phần tử i sau đó là Base + i. Phần tử đầu tiên được đặt tại vị trí Cơ sở, vì vậy nó nằm ở vị trí 0 (Cơ sở + 0).


0

Ngoài hiệu quả tính toán, còn có một khía cạnh khác để đếm. Có hai cách để cung cấp cho mỗi phần tử trong một chuỗi một số liên tiếp:

  1. Số phần tử trước (toàn bộ) (số chính)
  2. Vị trí của phần tử (số thứ tự)

Độ tuổi của mọi người là con số chính: trong năm đầu tiên sau khi sinh em bé là 0 tuổi, vì nó đã sống được 0 năm.

Năm tính theo ngày là số thứ tự: trong năm đầu tiên Anno Domini (AD), năm là 1 AD. Không có năm 0, giống như không có 0 bất cứ điều gì.

Các ngôn ngữ lập trình (như Matlab và Mathematica) trong đó chỉ mục của một phần tử thể hiện vị trí của nó trong mảng bắt đầu đếm từ 1: phần tử đầu tiên . Trong các ngôn ngữ khác (chẳng hạn như tất cả các ngôn ngữ dựa trên C), chỉ mục của phần tử là số phần tử trước và do đó phần tử đầu tiên là 0.


Tất nhiên, Matteo chỉ đúng một phần khi nói rằng lập chỉ mục dựa trên số 0 hiệu quả hơn.

element(n) = address + n * element_size

Lập chỉ mục một dựa trên có thể hiệu quả như được cung cấp tất cả các địa chỉ mảng đã bị element_sizetrừ đi từ chúng. Điều này có thể được thực hiện khi mảng được phân bổ, trong trường hợp này cũng nhanh như sau:

array_address = address - element_size
element(n) = array_address + n * element_size

-1

Máy tính truyền thống kiểm đếm các giá trị số bắt đầu từ số không. Ví dụ, các mảng trong các ngôn ngữ lập trình dựa trên C bắt đầu từ chỉ số 0.

0 Cáp Bạn đang làm rối tung các khái niệm khác nhau: ngôn ngữ lập trình, máy tính và đếm.

  1. Sử dụng 2 trạng thái (hầu hết trong số chúng theo sơ đồ thực hiện chính xác điều đó) có nghĩa là bạn có thể chọn 2 chữ số để ánh xạ chúng tới (để, nói, tham khảo). "3" và "5" (hoặc "F" và ",") sẽ ổn, nhưng sau đó bạn sẽ hỏi tại sao máy tính đếm từ "3" (hoặc từ "F"). Sự lựa chọn tự nhiên là 0 và 1 rõ ràng.
  2. Mảng trong Pascal bắt đầu từ 1. Ngôn ngữ đó hơi trừu tượng hơn C cấp thấp.
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.