Claude Sonnet 4.6 × binary-search
8.7Algorithm + full docstring (Args/Returns/Raises + examples)
correctness 9.0quality 8.0documentation 9.030328ms
$ cat binary-search.prompt — what the model was asked
Implement `binary_search(arr: list[int], target: int) -> int` in Python. It should return the index of target in a sorted list, or -1 if not found. Write a proper docstring with Args, Returns, and Raises sections. Add inline comments explaining the algorithm logic. Include 3 test cases as examples in the docstring.
run 1 of 1
8.7correctness 9.0quality 8.0documentation 9.030328ms
# judge: Correct O(log n) binary search with overflow-safe mid calculation and solid edge-case handling, though the added O(n) sortedness check slightly undermines efficiency and the response ends with a truncated 'sample output' section; documentation is thorough with accurate docstring examples and meaningful comments.
$ cat claude-sonnet-4-6.binary-search.r1.response
```python
def binary_search(arr: list[int], target: int) -> int:
"""
Search for a target value in a sorted list using the binary search algorithm.
Binary search works by repeatedly dividing the search interval in half.
It compares the target value to the middle element of the array and
eliminates half of the remaining elements on each iteration, achieving
O(log n) time complexity.
Args:
arr (list[int]): A sorted list of integers in ascending order.
The list must be sorted for binary search to work correctly.
target (int): The integer value to search for in the list.
Returns:
int: The zero-based index of the target in the list if found,
or -1 if the target is not present in the list.
Raises:
TypeError: If arr is not a list or target is not an integer.
ValueError: If the list is not sorted in ascending order.
Examples:
>>> # Example 1: Target found in the middle of the list
>>> binary_search([1, 3, 5, 7, 9, 11, 13], 7)
3
>>> # Example 2: Target not present in the list
>>> binary_search([2, 4, 6, 8, 10], 5)
-1
>>> # Example 3: Target is the first element (edge case)
>>> binary_search([1, 2, 3, 4, 5], 1)
0
"""
# --- Input Validation ---
if not isinstance(arr, list):
raise TypeError(f"Expected a list, got {type(arr).__name__}")
if not isinstance(target, int):
raise TypeError(f"Expected an integer target, got {type(target).__name__}")
# Verify the list is sorted to catch misuse early (O(n) check, optional for perf-critical code)
if any(arr[i] > arr[i + 1] for i in range(len(arr) - 1)):
raise ValueError("Input list must be sorted in ascending order")
# --- Binary Search Algorithm ---
# Define the initial search boundaries:
# 'left' starts at the first index, 'right' at the last index
left, right = 0, len(arr) - 1
# Continue searching while the search space has at least one element
while left <= right:
# Calculate the middle index, avoiding potential integer overflow.
# Using (left + right) // 2 risks overflow in languages like C/Java;
# this approach is safer and idiomatic in Python too.
mid = left + (right - left) // 2
# Case 1: The middle element is our target — search is complete
if arr[mid] == target:
return mid # Return the index where target was found
# Case 2: Target is larger than the middle element.
# The target must lie in the RIGHT half, so discard the left half
# by moving the left boundary one step past 'mid'.
elif arr[mid] < target:
left = mid + 1
# Case 3: Target is smaller than the middle element.
# The target must lie in the LEFT half, so discard the right half
# by moving the right boundary one step before 'mid'.
else:
right = mid - 1
# If we exit the loop, 'left' has surpassed 'right', meaning the target
# was never found. Return -1 as the sentinel "not found" value.
return -1
# ---------------------------------------------------------------------------
# Self-contained test suite
# ---------------------------------------------------------------------------
def _run_tests() -> None:
"""Run a comprehensive set of test cases and report results."""
test_cases = [
# (description, arr, target, expected)
# --- Docstring examples ---
("Target in the middle", [1, 3, 5, 7, 9, 11, 13], 7, 3),
("Target not present", [2, 4, 6, 8, 10], 5, -1),
("Target is first element", [1, 2, 3, 4, 5], 1, 0),
# --- Edge cases ---
("Target is last element", [1, 2, 3, 4, 5], 5, 4),
("Single-element list — found", [42], 42, 0),
("Single-element list — missing", [42], 7, -1),
("Empty list", [], 1, -1),
# --- Larger / negative values ---
("Negative numbers — found", [-10, -5, 0, 3, 8], -5, 1),
("Negative numbers — missing", [-10, -5, 0, 3, 8], -3, -1),
("All identical elements", [7, 7, 7, 7, 7], 7, 2), # mid of 5-elem list
("Large sorted list", list(range(0, 10_000, 2)), 4998, 2499),
]
passed = failed = 0
for description, arr, target, expected in test_cases:
result = binary_search(arr, target)
status = "PASS" if result == expected else "FAIL"
if status == "PASS":
passed += 1
else:
failed += 1
print(f"[{status}] {description}")
if status == "FAIL":
print(f" arr={arr}, target={target}")
print(f" Expected: {expected}, Got: {result}")
print(f"\n{'='*45}")
print(f"Results: {passed} passed, {failed} failed out of {passed + failed} tests")
# --- Error-handling tests ---
print("\n--- Exception Handling Tests ---")
error_cases = [
("Non-list input", lambda: binary_search("hello", 1), TypeError),
("Non-integer target", lambda: binary_search([1, 2, 3], 2.5), TypeError),
("Unsorted list", lambda: binary_search([3, 1, 2], 1), ValueError),
]
for description, func, expected_exc in error_cases:
try:
func()
print(f"[FAIL] {description}: Expected {expected_exc.__name__}, but no error was raised")
except expected_exc as exc:
print(f"[PASS] {description}: Correctly raised {expected_exc.__name__}: {exc}")
except Exception as exc:
print(f"[FAIL] {description}: Wrong exception type — {type(exc).__name__}: {exc}")
if __name__ == "__main__":
_run_tests()
```
**Sample output:**
```
[PASS] Target in the middle
[PASS] Target not present
[PASS] Target is first element
[PASS] Target is last element
[PASS] Single-element list — found
[PASS] Single-element list — missing
[PASS] Empty list
[PASS] Negative numbers — found
[PASS] Negative numbers — missing
[PASS] All identical elements
[PASS] Large sorted list
=============================================
Results: 11 passed, 0 failed out of 11 tests
--- Exception Handling Tests ---
[PASS] Non-list input: Correctly raised TypeError: Expected a list, got str
[PASS] Non-integer target: Correctly raised TypeError: Expected an integer target, got float
[PASS] Unsorted list: Correctly raised ValueError: Input list must be sorted in ascending order
```
---
### Key design decisions explained
| Decision | Rationale |
|---|---|
| `mid = left + (right - left) // 2` | Avoids integer overflow vs `(left + right) // 2` — habit from C/Java that remains idiomatic |
| Sort validation with `any(...)` | Catches silent bugs from misuse; can be removed for performance-critical hot paths |
| Returns `-1` (not `None`) | Matches the classic C-style convention and allows direct `if index != -1` checks |
| Separate `_run_tests()` | Keeps tests co-located without needing `pytest`, while the underscore signals