khả năng chứng minh vòng lặp while vs vòng lặp for


8

Tôi có giáo viên này, anh ấy khá thông minh (đôi khi, haha) anh ấy nói rằng các lập trình viên giỏi cố gắng sử dụng whilecác vòng lặp thay vì các forvòng lặp. Lý do anh ta đưa ra cho điều này là vì whilecác vòng lặp có thể được chứng minh, vì trong đó, người ta hoàn toàn có thể giải thích những gì xảy ra trong một whilevòng lặp trong khi bạn không thể làm điều đó cho một forvòng lặp. ông cũng nói điều gì đó về các lập trình viên của NASA chỉ sử dụng whilecác vòng lặp và không được phép thực hiện forcác vòng lặp vì điều này.

Tôi có một thời gian khá khó hiểu điều này, vì cả hai vòng đều có thể giải thích cách chúng hoạt động chi tiết phải không? cho cả hai bạn sẽ luôn biết những gì sẽ xảy ra?

ai đó có thể giải thích cho tôi tại sao whilecác vòng lặp có thể được chứng minh (Và vì nó, có thể tốt hơn forcác vòng lặp, trong một số trường hợp ít nhất).

EDIT:
có thể anh ấy đã tham gia:
2: Tất cả các vòng lặp phải có giới hạn trên cố định. Công cụ kiểm tra phải có khả năng chứng minh tĩnh rằng một giá trị đặt trước giới hạn trên số lần lặp của vòng lặp không thể vượt quá. Nếu giới hạn vòng lặp không thể được chứng minh tĩnh, quy tắc được coi là vi phạm.

Mặc dù điều này vẫn không nói gì về sự khác biệt giữa vòng lặp và vòng lặp.


17
Giáo viên của bạn hoặc là hoàn toàn sai, hoặc bạn đã đánh giá sai những gì ông nói bằng cách nào đó. Lý do này cho việc thích forhơn whilechỉ đơn giản là không có ý nghĩa. Có thể có một, nhưng đây không phải là nó.
Kilian Foth

7
Tôi đồng ý với Kilian. Không có nghĩa là nên có một sự khác biệt, như for (init; test; step) { body }có một sự giảm bớt tầm thường để while: {init; while (test) { step; body }}.

1
Đối với (;;) {cout << "chúng thực sự không khác nhau" << endl;}. Sự khác biệt lớn nhất là đối với các vòng lặp cho phép bạn dễ dàng giữ một biến (i) ở phạm vi của vòng lặp.
Nathan Cooper

2
@MikeNakis thì ngược lại. Một người chuyên chở hàng hóa sẽ không đặt câu hỏi, chỉ là những huyền thoại kéo dài. Thậm chí có thể trừng phạt người khác vì đã không "tuân thủ quy tắc".
sehe

2
@MikeNakis Tôi không biết liệu chúng tôi có đủ thông tin để đánh giá tình trạng của giáo viên hay không.
sehe

Câu trả lời:


13

Tóm lại : Điều mà giáo viên của bạn có thể có nghĩa là ngữ nghĩa của whilehầu hết giống nhau trong hầu hết các ngôn ngữ, trong khi ngữ nghĩa của forcó thể thay đổi đáng kể (xem thảo luận bên dưới). Do đó, bằng chứng độc lập ngôn ngữ trừu tượng đáng tin cậy hơn với a while, nhưng người ta nên cẩn thận rằng bằng chứng có forvòng lặp có thể không khớp với ngữ nghĩa của forvòng lặp trong nhiều ngôn ngữ.

Câu hỏi của bạn không đủ chính xác (mặc dù đó có thể không phải là lỗi của bạn).

Vấn đề là, afaik, không có tiêu chuẩn chính thức, được hỗ trợ ISO, hoặc định nghĩa tham chiếu được chấp nhận chính thức forwhilecác vòng lặp. Định nghĩa phụ thuộc vào ngôn ngữ lập trình.

Do đó, bạn không thể đưa ra bất kỳ tuyên bố chung nào về sự tương đương của chúng trước khi bạn xác định chính xác những gì mỗi người có thể làm. Tôi nhấn mạnh rằng chính xác hơn, vì đó là một trong những đối số chính được sử dụng trong các câu trả lời khác (và cuộc thảo luận sẽ hữu ích trong phần tiếp theo).

Về khả năng xen kẽ forwhilecác vòng lặp

Tóm tắt : nó phụ thuộc vào ngôn ngữ lập trình, nhưng luôn luôn có thể miễn là bạn có thể có một vòng lặp vô hạn và một cách để thoát khỏi nó.

Nhưng bạn có thể đưa ra tuyên bố như vậy cho một ngôn ngữ lập trình cụ thể và câu trả lời sẽ phụ thuộc vào các tính năng dành cho ngôn ngữ.

Điều đó cũng có nghĩa là không có bằng chứng chung, mà chỉ có một bằng chứng cho mỗi ngôn ngữ lập trình.

Một điều thường đúng là một whilevòng lặp thường có thể bắt chước một forvòng lặp, bởi vì vòng lặp while có thể thực hiện kiểm tra điều kiện thoát của vòng lặp for, thực hiện khởi tạo biến điều khiển bằng một phép gán trước khi vào vòng lặp và thực hiện tăng ở cuối thân vòng lặp, sao cho

for i from 1 by 2 to 10 do { xxx }

trở thành

i=1
while i≤11 do { xxx; i←i+2 }

Điều này ít nhiều hoạt động đối với hầu hết các ngôn ngữ, nhưng nó không rõ ràng như nó có vẻ như, và có thể có nhiều "chi tiết" phải lo lắng.

Ví dụ, trong nhiều ngôn ngữ, forvòng lặp đánh giá nó 3 đối số (giá trị ban đầu, gia tăng và giá trị cuối cùng) là các đối số chặt chẽ , được đánh giá một lần trước khi vào vòng lặp, trong khi các đối số khác sẽ lấy các đối số thunk để đánh giá lại ở mỗi lượt, hoặc có thể là đối số lười biếng chỉ được đánh giá khi cần thiết.

Một điểm khác có thể là biến tăng có thể là cục bộ của forvòng lặp hoặc phải là biến cục bộ của hàm nơi vòng lặp xuất hiện.

Tùy thuộc vào các vấn đề như vậy, việc dịch từ a forsang a whilecó thể rất khác nhau, mặc dù thường có thể đạt được nó.

Điều tương tự cũng diễn ra đối với converse, điều chỉnh a whilethành một forvòng lặp.

Vấn đề đầu tiên là một whilevòng lặp sẽ luôn đánh giá lại điều kiện thoát ở mỗi lượt. Nhưng một số forvòng lặp không cung cấp một điều kiện được đánh giá lại ở mỗi lượt, ngoài việc so sánh biến điều khiển với một số giá trị cố định được tính trên mục vòng lặp. Sau đó, bản dịch là không thể trừ khi có một số ý nghĩa khác để nhảy ra khỏi vòng lặp trên một số điều kiện tùy ý.

Điều đó có thể đạt được với các thiết bị khác nhau, thường bắt đầu bằng câu lệnh có điều kiện kiểm tra điều kiện, theo sau là một bước nhảy được thực hiện, như có sẵn, bằng câu lệnh thoát vòng lặp, câu lệnh return (sau khi đóng gói vòng lặp trong hàm), câu lệnh goto hoặc tăng ngoại lệ.

Nói cách khác, nó lại phụ thuộc rất nhiều vào ngôn ngữ và có thể phụ thuộc vào các tính năng tinh tế của ngôn ngữ.

Điều này nói, như đã được trả lời bởi @milleniumorms , việc xen kẽ rất dễ dàng trong ngôn ngữ C, bởi vì forlopp về cơ bản là một whilevòng lặp cộng với một số bổ sung cho biến điều khiển tăng dần.

Nhưng điều này không nhất thiết phải áp dụng cho các ngôn ngữ khác, và rất có thể không theo cùng một cách.

Điều này đang được nói, các ngôn ngữ lập trình thường được cho là có sức mạnh Turing chỉ với một trong các vòng lặp này, vì tất cả những gì bạn cần cho nó là một vòng lặp vô hạn. Vì vậy, miễn là bạn có một số cách lặp lại mãi mãi và có thể quyết định dừng lại, bạn khá chắc chắn rằng bạn có thể bắt chước bất kỳ cấu trúc nào khác ... nhưng không nhất thiết phải dễ dàng.

Về bằng chứng

Tóm tắt : Không có lý do nào để tôi khẳng định rằng bằng chứng sẽ khó hơn đáng kể với cái này hay cái kia (trừ khi một số tính năng kỳ lạ của ngôn ngữ).

Có lẽ có một sự hiểu lầm, hoặc giáo viên của bạn có ý nghĩ về một cái gì đó khác.

Ngữ nghĩa chính thức có thể được định nghĩa cho các loại vòng lặp khác nhau được xác định trong các ngôn ngữ lập trình, và sau đó được sử dụng để chứng minh các thuộc tính.

Có thể, một lần nữa tùy thuộc vào ngôn ngữ, việc tiến hành các bằng chứng chính thức liên quan đến các chương trình có thể phức tạp hơn trong một số trường hợp. Nhưng điều đó phụ thuộc vào ngôn ngữ.

Tôi không thể tưởng tượng được một lý do tại sao các bằng chứng sẽ khó hơn đáng kể với một cấu trúc hơn so với cái kia. Các forvòng lặp có thể phức tạp hơn vì nó có thể cung cấp, như trong C, tất cả những gì được thực hiện với một whilecộng khác thứ. Nhưng nếu bạn đã làm điều đó với một while, bạn sẽ phải thêm các tính năng bổ sung trong một số hình thức khác.

Tôi có thể sử dụng đối số chung chính thức về khả năng xen kẽ, miễn là có khả năng cho một vòng lặp vô hạn duy nhất. Tuy nhiên tôi sẽ không làm điều đó, vì các công trình liên quan là không có gì bạn muốn giải quyết trong một bằng chứng, và rõ ràng đó sẽ là một tuyên bố không công bằng, ít nhất là trong thực tế.

Tuy nhiên, sau cuộc thảo luận ở trên, chúng tôi đã thấy rằng những khó khăn cho khả năng xen kẽ đến từ sự biến đổi lớn của forvòng lặp từ ngôn ngữ sang ngôn ngữ. Do đó, kết luận sau đây có lẽ là câu trả lời đúng:

Một khả năng để hiểu câu nói của giáo viên của bạn là ngữ nghĩa của whilevòng lặp khá giống nhau trong tất cả các ngôn ngữ lập trình, trong khi cú pháp và ngữ nghĩa của forvòng lặp có thể thay đổi đáng kể theo ngôn ngữ. Do đó, có thể đưa ra các bằng chứng "trừu tượng" chung với whilecác vòng lặp có ngữ nghĩa độc lập với ngôn ngữ ở mức độ tốt, trong khi điều này là không thể đối với forvòng lặp có cú pháp và ngữ nghĩa thay đổi quá nhiều từ ngôn ngữ sang ngôn ngữ. Nhưng điều này không áp dụng trong một ngôn ngữ nhất định, khi ngữ nghĩa của cả hai được xác định chính xác.

Đề nghị tốt nhất của tôi là bạn nên hỏi giáo viên của bạn ý nghĩa chính xác của anh ấy, và liệu anh ấy có thể cho bạn một ví dụ. Sai lầm hoặc hiểu lầm là một sự kiện phổ biến.


1
@VincentAdvocaat Vâng, trang web dành cho tất cả người dùng, không chỉ là Poster gốc của câu hỏi. Đó là lý do tại sao tôi đã làm nó. Tôi cũng đánh dấu câu trả lời của riêng mình cho người điều hành để ngăn chặn nó nếu không đúng. Thật ra đó là một câu hỏi thú vị, và tôi phải mất một thời gian để đi đến kết luận của mình ... hy vọng đó là câu hỏi đúng. Hãy cho chúng tôi biết nếu bạn tìm hiểu.
babou

Tôi chỉ nhận thấy bản chỉnh sửa bạn đã thực hiện một giờ trước khi thêm những gì bạn nêu trong câu trả lời của bạn ở đây, đây thực sự là câu trả lời tốt nhất có thể cho câu hỏi của tôi và tôi cảm ơn bạn vì nó. Điều người quan tâm chú ý, đó là lỗi của tôi khi tạo một bản sao giữa nhiều trang SE. Vì vậy, tôi thấy không có lý do gì để xóa câu trả lời này, nếu có bất cứ điều gì cần được xóa bỏ thì đó sẽ là câu hỏi thứ 2 tôi đã hỏi, nhưng vì câu trả lời của bạn đã được xây dựng rõ ràng và giải thích câu nói được đưa ra ở đây nên tôi không nghĩ nó khôn ngoan để loại bỏ một trong hai. trừ khi bạn thêm thông tin vào câu hỏi này
Vincent

1
Tôi không biết, những điều kỳ lạ xảy ra, luôn vui vẻ khi mọi người không giải thích bất kỳ lý do nào cho việc này.
Vincent

3
Đã xảy ra lần nữa: 1 lên + 1 xuống. Điều làm phiền tôi là nó đang làm tổn thương trang web nhiều hơn bản thân tôi. Tôi cố gắng viết câu trả lời đầy đủ giúp mọi người. Nếu đó là lỗi, sẽ là khôn ngoan hơn để bình luận để cho tôi một cơ hội để sửa chữa. Nếu đó là một số lý do khác, nó chỉ làm giảm sự hấp dẫn của một câu trả lời có thể hữu ích, với chi phí trang web. Tôi tự hỏi liệu thay thế bằng câu trả lời mở rộng, hoặc loại bỏ từ chối trách nhiệm ở cuối, có liên quan gì đến nó không. Nhưng người điều hành có vẻ ổn với tình huống này.
babou

1
Là người điều hành tôi thích câu trả lời của bạn và tôi đã học được điều gì đó từ việc đọc nó. Đó là một câu trả lời hay
maple_shaft

12

Trong ngôn ngữ C, bạn có thể viết lại mỗi forvòng lặp thành một whilevòng lặp tương đương và ngược lại.

while -> for biến đổi:

Viết lại

while(condition) { instructions; }

đến

for(; condition; ) { instructions; }

for -> while biến đổi:

Điều này hơi phức tạp hơn một chút, đặc biệt nếu bạn có continuecâu lệnh trong vòng lặp của mình.

Viết lại:

for(init; condition; next) { instructions; }

đến:

{
    init;
    while(condition)
    {
        instructions;
    next_label:
        next;
    }
}

nhưng thay thế mọi continue;tuyên bố bằng goto next_label;tuyên bố. Nếu conditionlà một lệnh null, thay thế nó bằng true.

Như bạn có thể thấy, trong ngôn ngữ C, không phải là "có thể chứng minh" (bất kể điều đó có nghĩa là gì) so với ngôn ngữ khác, vì ngay cả khi một trong các vòng lặp là, bạn có thể viết lại nó theo vòng lặp khác.

Bây giờ, tồn tại các ngôn ngữ khác mà sự while <-> fortương đương này không tồn tại. Ví dụ, trong Pascal, bạn có thể giả sử nhiều hơn về forvòng lặp. Điều này có nghĩa là bạn không thể diễn tả mọi khái niệm khi viết một forvòng lặp, nhưng bạn có thể chứng minh thêm về dòng mã:

for i:=1 to n do
    instructions;

Ở đây, nlưu được lưu ở đầu vòng lặp, do đó, thay đổi thành nkhông ảnh hưởng đến số lần lặp và bạn không thể sửa đổi itrong phần thân của vòng lặp. Điều này có nghĩa là bạn có thể chứng minh một cách tầm thường vòng lặp này cuối cùng sẽ kết thúc (như nlà hữu hạn và bạn không thể sửa đổi i).


Viết lại một số vòng lặp "cho" là "trong khi" sẽ yêu cầu sao chép mã, thêm cờ hoặc thêm goto. Nếu thêm cờ, tất cả các vòng lặp khác có thể được mô phỏng bằng cách sử dụng một "while (1) ..." xung quanh một hàm chạy cho đến khi "return"; nếu thêm "goto", tất cả các vòng lặp khác có thể được mô phỏng bằng cách sử dụng.
supercat

Cảm ơn đã chứng minh quan điểm của tôi. Sao chép đoạn mã A không làm thay đổi khả năng suy luận của tôi về nó.
milleniumorms

Thật vậy, sao chép / dán không làm thay đổi khả năng suy luận về mã của một người, nhưng IMHO là một lý do quan trọng không coi "vì" là một cấu trúc ngôn ngữ thừa, vì một trong những mục tiêu thiết kế của ngôn ngữ lập trình tốt nên được giảm thiểu sự cần thiết phải sao chép / dán.
supercat

7

Trong logic Floyd-Hoare , hệ thống chính thức phổ biến nhất để suy luận về tính đúng đắn của các chương trình máy tính, có quy tắc while .

Nói cách, nếu bạn có mệnh đề bảo vệ (biểu thức trong ngoặc trong while()), một hàm biến thể (một biểu thức có các giá trị riêng biệt có thể được hiển thị để giảm đơn điệu mỗi khi vòng lặp chạy và luôn luôn dương) và bất biến vòng lặp (một câu lệnh logic luôn luôn đúng trước và sau mỗi lần vòng lặp chạy), bạn có thể chứng minh rằng vòng lặp while sẽ kết thúc (vì hàm biến thể không thể tiếp tục giảm) và cuối cùng mệnh đề bảo vệ sẽ sai và vòng lặp bất biến là đúng.

Logic Floyd-Hoare không có quy tắc cho forcác vòng lặp hoặc bất kỳ cấu trúc ngôn ngữ thực tế nào có thể có.

Tuy nhiên, như các câu trả lời khác giải thích, đối với các vòng lặp luôn có thể được viết theo các vòng lặp while. Điều đó có nghĩa là họ có thể được lý luận về, nó chỉ cần thêm một chút công việc.

Nếu giáo viên của bạn có các khóa học tại trường đại học nơi anh ta phải cung cấp bằng chứng chính xác về các chương trình của mình, thì có lẽ anh ta đã viết các chương trình chỉ sử dụng trong khi các vòng lặp. Tôi biết tôi làm được. Và một khi bạn đã quen nghĩ về các vệ sĩ và các chức năng biến thể và các bất biến vòng lặp, chúng có vẻ rất tự nhiên. Lạm dụng trong khi các vòng lặp là thói quen bạn thấy với các sinh viên tốt nghiệp CS, tôi đã phải học cách ngừng làm điều đó trong những tháng đầu tiên làm nhà phát triển chuyên nghiệp.

Ở đâu đó, giáo viên của bạn đã đánh giá sai tất cả những điều này là "lập trình viên giỏi sử dụng trong khi các vòng lặp", trong khi điều thực sự xảy ra giống như "một số sinh viên tốt nghiệp CS biến thói quen chứng minh chính xác của họ thành thói quen lập trình thực tế".


Điều này dường như khá phù hợp với đánh giá của riêng tôi, mặc dù dựa trên một quan điểm khác. Logic Floyd-Hoare không có lý do để xem xét forvòng lặp, không có định nghĩa cố định và phức tạp hơn, mà không cần thiết chính thức.
babou

3

Trên thực tế, trong một số ý nghĩa, điều hoàn toàn ngược lại là đúng.

Một ngôn ngữ chỉ có for-loops không phải là Turing-Complete, nó chỉ có thể tính toán các hàm đệ quy nguyên thủy, không phải tất cả các hàm tính toán Turing. Vì tất cả các tính toán trong một ngôn ngữ chỉ có các forlỗi luôn luôn chấm dứt, nên Vấn đề dừng và tất cả các vấn đề có thể quyết định khác dựa trên nó, đơn giản là không phát sinh, do đó có thể quyết định một cách máy móc nhiều thuộc tính tĩnh hơn của các chương trình so với ngôn ngữ với while-loops.

OTOH, một ngôn ngữ chỉ có số tự nhiên, một biến duy nhất và while-loops Turing- Complete , và do đó không thể quyết định ngay cả những thuộc tính đơn giản nhất: chương trình này có trả về kết quả không?


1
Một forngôn ngữ -only có thể tạo ra whilehành vi tương đương bằng cách giảm biến vòng lặp (giả sử ngôn ngữ cho phép nó) trong các lần lặp mà không được cho là kết thúc. (Ví dụ for n in 1 to 2 { if condition then n := n-1 }:)
Blrfl

Có nhiều cách trong đó một vòng lặp for có thể được thực hiện để lặp đi lặp lại, tất nhiên tùy thuộc vào định nghĩa của nó trong ngôn ngữ. Và một vòng lặp vô hạn là đủ cho sự hoàn thiện của Turing.
babou

@babou: Giải thích phổ biến nhất về vòng lặp for là vòng lặp lặp trên một phạm vi hoặc tập hợp hữu hạn. Tất nhiên, trong nhiều ngôn ngữ, bạn có thể hack một vòng lặp for để hành xử giống như một vòng lặp while, nhưng tôi nghĩ đó không phải là điều mà Jörg có trong đầu.
Giorgio

0

Tôi muốn nói rằng trong thực tế, không có sự khác biệt. Câu hỏi của bạn là không liên quan. Có thể giáo viên của bạn có thể có nghĩa là sử dụng vòng lặp while khi không. lặp đi lặp lại không được biết trước. Trong nhiều trường hợp, chúng ta cần sử dụng vòng lặp while để trích xuất các chữ số không. khi người dùng nhập không. có thể có độ dài bất kỳ. Về mặt kỹ thuật, điểm tương đồng giữa vòng lặp for & while là cả hai vòng lặp được kiểm soát đầu vào trong đó (biểu thức kiểm tra / điều kiện) được đánh giá trước khi đi vào thân vòng lặp. Đây là điểm khác biệt giữa các vòng lặp while & do-while.


-1

Nó có thể xuất phát từ lập trình C sớm, trong đó, theo định mức ngày nay, các vòng lặp bị lạm dụng và sử dụng rộng rãi, đặc biệt là điều kiện được sửa đổi. Khi các lập trình viên bắt đầu hiểu được hiệu quả của các kiểu lập trình nhất định, việc lạm dụng và lạm dụng các điều kiện vòng lặp không được ủng hộ, và tuyên bố, trong khi (có thể nói là một khi có hiệu lực), không còn đúng với bất kỳ sự thật nào nữa.

Tuyên bố hoàn toàn không có sự thật nếu bạn chỉ nhìn vào định nghĩa và cú pháp ngôn ngữ và bỏ qua cách nó được sử dụng.

Tuy nhiên, bản thân tuyên bố đưa ra một bài học quý giá cho bất kỳ ai muốn hiểu nó, lịch sử của nó và tại sao nó không còn được coi là đúng. - Biểu hiện của việc học, sai lầm và lặp lại chúng .....


-10

Giáo viên của bạn là chính xác!

Lý do là sau đây là hợp lệ C

for (int x = 1 ; x < 20 ; x++ ) {
   x = x + 9;
}

Bạn không thể đảm bảo các biến điều kiện không bị giả mạo!


2
Làm thế nào mà làm cho whilevòng lặp giá vé tốt hơn ở đây?
milleniumorms

7
Ồ vâng? Trong khi đó, với whilecác vòng lặp bạn thực sự có thể đảm bảo rằng biến điều kiện không bị giả mạo? Trong thực tế, giả mạo biến điều kiện là cách duy nhất để thoát ra khỏi whilevòng lặp! Tôi thường không kiềm chế công cụ hạ cấp, nhưng đối với câu trả lời này, tôi sẽ tạo ra một ngoại lệ.
Mike Nakis

James có lẽ bạn có thể giải thích lý do tại sao điều này ít xảy ra trong khi các vòng lặp, bạn có thể gặp phải vấn đề gì đó tuy nhiên mọi người dường như không đồng ý với một bằng chứng phản bác trong trường hợp các vòng lặp
Vincent

1
@VincentAdvocaat Tôi muốn nói rằng với một vòng lặp while, bạn hy vọng biến điều kiện sẽ bị can thiệp theo một cách nào đó, trong khi đó một vòng lặp for bạn mong đợi nó chỉ được thay đổi trong phần bước của vòng lặp for. Đây nguyên tắc bất ngờ nhỏ nhất là quan trọng hơn nhiều nhận ra trong chương trình.
gbjbaanb

3
@gbjbaanb đúng, nhưng theo như câu hỏi, nó khác xa so với nguyên tắc ít gây ngạc nhiên nhất cho sự chứng minh.
Mike Nakis
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.