Recent from talks
Nothing was collected or created yet.
Correctness (computer science)
View on WikipediaIn theoretical computer science, an algorithm is correct with respect to a specification if it behaves as specified. Best explored is functional correctness, which refers to the input–output behavior of the algorithm: for each input it produces an output satisfying the specification.[1]
Within the latter notion, partial correctness, requiring that if an answer is returned it will be correct, is distinguished from total correctness, which additionally requires that an answer is eventually returned, i.e. the algorithm terminates. Correspondingly, to prove a program's total correctness, it is sufficient to prove its partial correctness, and its termination.[2] The latter kind of proof (termination proof) can never be fully automated, since the halting problem is undecidable.
| Partially correct C program to find the least odd perfect number, its total correctness is unknown as of 2023 |
// return the sum of proper divisors of n
static int divisorSum(int n) {
int i, sum = 0;
for (i=1; i<n; ++i)
if (n % i == 0)
sum += i;
return sum;
}
// return the least odd perfect number
int leastPerfectNumber(void) {
int n;
for (n=1; ; n+=2)
if (n == divisorSum(n))
return n;
}
|
For example, successively searching through integers 1, 2, 3, … to see if we can find an example of some phenomenon—say an odd perfect number—it is quite easy to write a partially correct program (see box). But to say this program is totally correct would be to assert something currently not known in number theory.
A proof would have to be a mathematical proof, assuming both the algorithm and specification are given formally. In particular it is not expected to be a correctness assertion for a given program implementing the algorithm on a given machine. That would involve such considerations as limitations on computer memory.
A deep result in proof theory, the Curry–Howard correspondence, states that a proof of functional correctness in constructive logic corresponds to a certain program in the lambda calculus. Converting a proof in this way is called program extraction.
Hoare logic is a specific formal system for reasoning rigorously about the correctness of computer programs.[3] It uses axiomatic techniques to define programming language semantics and argue about the correctness of programs through assertions known as Hoare triples.
Software testing is any activity aimed at evaluating an attribute or capability of a program or system and determining that it meets its required results. Although crucial to software quality and widely deployed by programmers and testers, software testing still remains an art, due to limited understanding of the principles of software. The difficulty in software testing stems from the complexity of software: we can not completely test a program with moderate complexity. Testing is more than just debugging. The purpose of testing can be quality assurance, verification and validation, or reliability estimation. Testing can be used as a generic metric as well. Correctness testing and reliability testing are two major areas of testing. Software testing is a trade-off between budget, time and quality.[4]
See also
[edit]Notes
[edit]- ^ Dunlop, Douglas D.; Basili, Victor R. (June 1982). "A Comparative Analysis of Functional Correctness". Communications of the ACM. 14 (2): 229–244. doi:10.1145/356876.356881. S2CID 18627112.
- ^ Manna, Zohar; Pnueli, Amir (September 1974). "Axiomatic approach to total correctness of programs". Acta Informatica. 3 (3): 243–263. doi:10.1007/BF00288637. S2CID 2988073.
- ^ Hoare, C. A. R. (October 1969). "An axiomatic basis for computer programming" (PDF). Communications of the ACM. 12 (10): 576–580. CiteSeerX 10.1.1.116.2392. doi:10.1145/363235.363259. S2CID 207726175. Archived from the original (PDF) on 4 March 2016.
- ^ Pan, Jiantao (Spring 1999). "Software Testing" (coursework). Carnegie Mellon University. Retrieved 21 November 2017.
References
[edit]- "Human Language Technology. Challenges for Computer Science and Linguistics." Google Books. N.p., n.d. Web. 10 April 2017.
- "Security in Computing and Communications." Google Books. N.p., n.d. Web. 10 April 2017.
- "The Halting Problem of Alan Turing - A Most Merry and Illustrated Explanation." The Halting Problem of Alan Turing - A Most Merry and Illustrated Explanation. N.p., n.d. Web. 10 April 2017.
- Turner, Raymond, and Nicola Angius. "The Philosophy of Computer Science." Stanford Encyclopedia of Philosophy. Stanford University, 20 August 2013. Web. 10 April 2017.
- Dijkstra, E. W. "Program Correctness". U of Texas at Austin, Departments of Mathematics and Computer Sciences, Automatic Theorem Proving Project, 1970. Web.
Correctness (computer science)
View on GrokipediaOverview
Definition
In computer science, correctness denotes the property of a program or algorithm whereby it produces outputs that conform precisely to its intended specification for every valid input, ensuring that the computed results match the expected behavior as defined by the program's requirements. This concept, foundational to software engineering and theoretical computing, emphasizes that a correct program accomplishes the intentions of its designers and users without deviation, no more and no less.[4][6] A key distinction exists between program correctness and numerical accuracy in computing contexts, such as floating-point arithmetic. While numerical accuracy focuses on the precision and error bounds of computational results—often measured in terms of relative or absolute deviations—correctness pertains solely to the functional relationship between inputs and outputs, irrespective of any inherent approximation in the representation or calculation of values. For example, a program computing the square root might be numerically accurate to a specified precision but incorrect if it fails to handle edge cases like negative inputs as per its specification.[7][8] The role of specifications is central to assessing correctness, serving as the unambiguous benchmark against which program behavior is evaluated. Informal specifications, typically expressed in natural language or pseudocode, provide high-level descriptions of expected functionality but may introduce ambiguity due to their non-mathematical nature. In contrast, formal specifications use rigorous mathematical notations, such as predicate logic or temporal logics, to define precise preconditions, postconditions, and invariants, enabling verifiable proofs of correctness.[9][6] A representative example is a sorting algorithm, which is deemed correct if it transforms any input list of comparable elements into a list sorted in non-decreasing order, preserving the multiset of original elements without alteration. For instance, applying the algorithm to the list [3, 1, 4, 1, 5] should yield [1, 1, 3, 4, 5], satisfying the specification for all possible inputs. Correctness in this sense is often analyzed through partial correctness (assuming termination) and total correctness (including guaranteed termination), concepts detailed in later sections.[10][8]Importance in Computing
Ensuring correctness in software is paramount due to the severe risks posed by incorrect programs, which can lead to catastrophic failures in real-world applications. For instance, the 1996 Ariane 5 rocket explosion occurred 37 seconds after launch when a software error in the inertial reference system caused an operand error, resulting in the vehicle's self-destruction and the loss of a $370 million payload.[11] Similarly, the Therac-25 radiation therapy machine in the 1980s delivered massive overdoses to at least six patients between 1985 and 1987 due to software bugs involving race conditions and inadequate error handling, leading to three fatalities and multiple severe injuries.[12] These incidents underscore how software flaws can cause loss of life, financial devastation, and erosion of public trust in technology. The benefits of prioritizing correctness are especially pronounced in safety-critical systems, where reliability directly safeguards human lives and infrastructure. In avionics, standards like DO-178C mandate rigorous processes to verify software correctness, ensuring flight control systems operate without failure in environments like commercial aircraft.[13] For medical devices, such as pacemakers and infusion pumps, correctness prevents malfunctions that could harm patients, with regulatory frameworks like IEC 62304 emphasizing software lifecycle activities to achieve this.[14] Moreover, achieving correctness early in development yields substantial cost savings; a 2022 report estimates that poor software quality costs the U.S. economy $2.41 trillion annually, with nearly half of a large software system's long-term budget spent on finding and fixing bugs post-deployment, where such external failure costs are an order of magnitude higher than internal pre-release fixes.[15] However, pursuing correctness often involves trade-offs with other priorities, such as performance, usability, and development time. Enhancing correctness through extensive testing or modular design may increase computational overhead, potentially degrading system speed in resource-constrained environments like embedded devices.[16] Similarly, rigorous correctness checks can extend timelines, as developers balance thorough validation against market pressures for rapid releases, sometimes compromising on edge-case handling to meet deadlines.[17] These tensions highlight the need for strategic decisions in software architecture to mitigate impacts on usability, where overly restrictive correctness measures might hinder intuitive interfaces. Correctness plays an integral role throughout the software engineering lifecycle, from requirements elicitation to deployment and maintenance, to preempt defects and ensure alignment with specifications. During requirements and design phases, defining precise behaviors facilitates downstream verification, reducing ambiguity that leads to errors.[18] In implementation and testing, techniques like unit testing and integration checks embed correctness as a core practice, while post-deployment monitoring sustains it against evolving conditions.[18] Verification methods, such as static analysis and model checking, serve as key approaches to realize this integration across the lifecycle.Types of Correctness
Partial Correctness
Partial correctness is a fundamental notion in program verification that concerns the behavior of a program upon termination, without requiring that the program actually terminates. It asserts that if a program starts in a state satisfying a given precondition and executes to completion, then the resulting state satisfies the specified postcondition. This concept forms the basis of Hoare logic, introduced by C. A. R. Hoare, which provides a formal framework for reasoning about such properties.[19] In Hoare logic, partial correctness is expressed using Hoare triples of the form {P} S {Q}, where P is the precondition (a logical assertion true before executing statement S), S is the program statement or sequence of statements, and Q is the postcondition (a logical assertion that must hold after S terminates if P held initially). Semantically, the triple {P} S {Q} is valid if, whenever the initial state satisfies P and the execution of S terminates, the final state satisfies Q. Non-terminating executions are considered vacuously correct under this semantics, as they do not produce a final state to falsify Q. This formulation allows verification of functional correctness independently of termination concerns.[19][20] A key technique for establishing partial correctness in loops is the use of loop invariants, which are assertions that remain true before and after each iteration of the loop. Consider a binary search algorithm on a sorted array a of length n to find a key k. The precondition might be that a is sorted in non-decreasing order and 1 ≤ lower ≤ upper ≤ n. The loop maintains the invariant that k is present in the subarray a[lower..upper] if and only if it is present anywhere in a, along with bounds lower ≤ mid ≤ upper. The loop body computes mid as the midpoint, compares k with a[mid], and narrows the search interval accordingly. Upon loop exit (when lower > upper), the postcondition holds: if k was found, its index is returned; otherwise, it is reported as absent. This invariant ensures partial correctness, as the search preserves the presence property throughout. In theoretical settings with infinite inputs, such as searching an unbounded sorted sequence, the algorithm may not terminate if k is absent or beyond the initial segment, but partial correctness still guarantees that any terminating execution yields the correct result.[21] The primary limitation of partial correctness is that it disregards non-termination, treating infinite loops as acceptable outcomes rather than errors. This makes it particularly useful for verifying programs in infinite-state systems, where proving termination is generally undecidable due to the halting problem, allowing focus on behavioral properties when execution completes. Total correctness extends partial correctness by additionally requiring termination, but partial correctness alone suffices for many practical verification tasks.[22][23]Total Correctness
Total correctness extends partial correctness by additionally requiring that the program terminates in a finite number of steps for all initial states satisfying the precondition. In the notation of Hoare logic, a triple {P} S {Q} denotes total correctness if, whenever the program S begins execution in a state where precondition P holds, S is guaranteed to terminate and the resulting state satisfies postcondition Q.[24] This formulation ensures both the functional behavior (as in partial correctness) and liveness through termination.[24] Proving termination often relies on ranking functions, which map program states to elements of a well-founded set, such as the natural numbers, such that the ranking decreases strictly with each transition until reaching a base case.[25] Well-founded orders, like the standard ordering on naturals, prevent infinite descent, thereby establishing that execution paths are finite.[25] These functions are synthesized or inferred to cover loops and recursive calls, providing a rigorous argument for bounded execution time. A classic example is the recursive computation of the factorial function, where the precondition is (an integer) and the postcondition is that the result equals . The following pseudocode illustrates the structure:function fact(n):
if n ≤ 1:
return 1
else:
return n * fact(n - 1)
function fact(n):
if n ≤ 1:
return 1
else:
return n * fact(n - 1)
