Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- **
- * Checks if three given side lengths can form a valid, non-degenerate triangle.
- *
- * The triangle inequality theorem states that the sum of the lengths of any
- * two sides of a triangle must be strictly greater than the length of the
- * third side.
- *
- * This implementation handles large numbers up to Number.MAX_VALUE, incorporates
- * tolerance for floating-point inaccuracies (e.g., 0.1, 0.2, 0.3 -> false),
- * and includes specific checks for edge cases involving Number.MAX_VALUE where
- * standard arithmetic might fail due to precision limits (e.g., MAX + 1 === MAX).
- *
- * @param a - Length of the first side. Must be a positive finite number.
- * @param b - Length of the second side. Must be a positive finite number.
- * @param c - Length of the third side. Must be a positive finite number.
- * @returns True if the sides can form a valid, non-degenerate triangle, false otherwise.
- */
- function isTriangle(a: number, b: number, c: number): boolean {
- // 1. Basic validity checks: sides must be positive and finite numbers.
- if (a <= 0 || b <= 0 || c <= 0 ||
- !Number.isFinite(a) || !Number.isFinite(b) || !Number.isFinite(c)) {
- return false;
- }
- // --- Refined Special Case Handling for MAX_VALUE ---
- // Handles cases where standard arithmetic fails due to precision (MAX+1=MAX)
- // ONLY for configurations guaranteed to be valid triangles.
- const max = Number.MAX_VALUE;
- const aIsMax = (a === max);
- const bIsMax = (b === max);
- const cIsMax = (c === max);
- if (aIsMax && bIsMax && cIsMax) {
- // Case (MAX, MAX, MAX) -> Valid
- return true;
- }
- if (aIsMax && bIsMax && !cIsMax) {
- // Case (MAX, MAX, c) where c is finite positive -> Valid
- return true;
- }
- // Case (MAX, b, MAX) where b is finite positive:
- // This is degenerate (a+b=c due to precision). Let general checks handle it.
- // No 'return true' here.
- // Case (a, MAX, MAX) where a is finite positive:
- // This is degenerate (a+b=c due to precision). Let general checks handle it.
- // No 'return true' here.
- // --- End Special Case ---
- // 2. General Triangle Inequality Check with Tolerance
- // For all other cases, including (MAX, b, MAX) and (a, MAX, MAX).
- // Tolerance is scaled based on max side involved in each comparison.
- // Check 1: a + b > c?
- // Use Math.max(a,b,c) for consistent tolerance scaling across checks
- const maxSide = Math.max(a, b, c); // Calculate once if possible
- // Note: Math.max works correctly even with large numbers, but not Infinity.
- // However, Infinity inputs are already rejected by isFinite check.
- const tolerance = Number.EPSILON * maxSide * 2;
- // Check the difference against the tolerance.
- // `a + b - c` handles potential Infinity in `a+b` correctly if c is finite.
- if (a + b - c <= tolerance) {
- return false;
- }
- // Check 2: a + c > b?
- // Re-use the same tolerance for consistency and slight optimization
- if (a + c - b <= tolerance) {
- return false;
- }
- // Check 3: b + c > a?
- // Re-use the same tolerance
- if (b + c - a <= tolerance) {
- return false;
- }
- // If all checks passed, it's a valid, non-degenerate triangle.
- return true;
- }
- // --- Native TypeScript Test Suite (same as previous versions) ---
- console.log("Starting Triangle Validity Tests...\n");
- let passed = 0;
- let failed = 0;
- function runTest(description: string, expected: boolean, actual: boolean) {
- const result = expected === actual;
- if (result) {
- console.log(`✅ PASS: ${description}`);
- passed++;
- } else {
- console.error(`❌ FAIL: ${description} (Expected: ${expected}, Got: ${actual})`);
- failed++;
- }
- }
- // --- Test Cases (including the one that failed previously) ---
- // 1. Equivalence Classes: Valid Triangles
- console.log("--- Valid Triangles ---");
- runTest("Equilateral (small)", true, isTriangle(5, 5, 5));
- runTest("Equilateral (large)", true, isTriangle(1e100, 1e100, 1e100));
- runTest("Isosceles (small)", true, isTriangle(5, 5, 8));
- runTest("Isosceles (base > leg)", true, isTriangle(8, 8, 5));
- runTest("Isosceles (large)", true, isTriangle(1e50, 1e50, 1.5e50));
- runTest("Scalene (small)", true, isTriangle(3, 4, 5)); // Right triangle
- runTest("Scalene (obtuse)", true, isTriangle(3, 5, 7));
- runTest("Scalene (acute)", true, isTriangle(5, 6, 7));
- runTest("Scalene (large)", true, isTriangle(1e10, 1.2e10, 1.5e10));
- runTest("Sides very close", true, isTriangle(10, 10, 10 + Number.EPSILON * 100));
- // 2. Equivalence Classes: Degenerate Triangles (Should return false)
- console.log("\n--- Degenerate Triangles (Expect False) ---");
- runTest("Degenerate (exact sum: 1, 2, 3)", false, isTriangle(1, 2, 3));
- runTest("Degenerate (exact sum: 3, 1, 2)", false, isTriangle(3, 1, 2));
- runTest("Degenerate (exact sum: 2, 3, 1)", false, isTriangle(2, 3, 1));
- runTest("Degenerate (large exact sum)", false, isTriangle(1e50, 2e50, 3e50));
- runTest("Degenerate (floating point: 0.1, 0.2, 0.3)", false, isTriangle(0.1, 0.2, 0.3));
- runTest("Degenerate (floating point: 0.3, 0.1, 0.2)", false, isTriangle(0.3, 0.1, 0.2));
- runTest("Degenerate (floating point: 0.2, 0.3, 0.1)", false, isTriangle(0.2, 0.3, 0.1));
- const slightlyOffA = 0.1;
- const slightlyOffB = 0.2;
- const slightlyOffC = 0.3 + Number.EPSILON;
- runTest("Degenerate (A+B almost equal C, C slightly larger)", false, isTriangle(slightlyOffA, slightlyOffB, slightlyOffC));
- const slightlyOffC2 = 0.3 - Number.EPSILON;
- runTest("Near Degenerate (A+B barely greater than C)", true, isTriangle(slightlyOffA, slightlyOffB, slightlyOffC2));
- // 3. Equivalence Classes: Impossible Triangles (Should return false)
- console.log("\n--- Impossible Triangles (Expect False) ---");
- runTest("Impossible (1, 1, 3)", false, isTriangle(1, 1, 3));
- runTest("Impossible (3, 1, 1)", false, isTriangle(3, 1, 1));
- runTest("Impossible (1, 3, 1)", false, isTriangle(1, 3, 1));
- runTest("Impossible (large)", false, isTriangle(1e100, 1e100, 3e100));
- runTest("Impossible (one side much larger)", false, isTriangle(5, 8, 100));
- // 4. Boundary / Edge Cases
- console.log("\n--- Boundary & Edge Cases ---");
- // 4.1 Zero and Negative Sides
- runTest("Zero side (a=0)", false, isTriangle(0, 5, 5));
- runTest("Zero side (b=0)", false, isTriangle(5, 0, 5));
- runTest("Zero side (c=0)", false, isTriangle(5, 5, 0));
- runTest("All zero sides", false, isTriangle(0, 0, 0));
- runTest("Negative side (a<0)", false, isTriangle(-1, 5, 5));
- runTest("Negative side (b<0)", false, isTriangle(5, -1, 5));
- runTest("Negative side (c<0)", false, isTriangle(5, 5, -1));
- runTest("All negative sides", false, isTriangle(-1, -2, -3));
- // 4.2 Very Small Positive Sides
- const tiny = Number.MIN_VALUE;
- const tinyEps = Number.EPSILON;
- runTest("Very small equilateral", true, isTriangle(tiny, tiny, tiny));
- runTest("Very small isosceles", true, isTriangle(tiny * 2, tiny * 2, tiny));
- runTest("Very small scalene", true, isTriangle(tiny * 3, tiny * 4, tiny * 5));
- runTest("Very small degenerate", false, isTriangle(tiny, tiny * 2, tiny * 3));
- runTest("Near zero, almost degenerate", false, isTriangle(tinyEps, tinyEps, 2 * tinyEps));
- runTest("Near zero, valid", true, isTriangle(tinyEps * 2, tinyEps * 2, tinyEps * 3));
- // 4.3 Very Large Positive Sides (Near MAX_VALUE)
- const max = Number.MAX_VALUE;
- const maxHalf = max / 2;
- const maxSlightlyLess = max * (1 - Number.EPSILON * 10);
- runTest("Max value equilateral", true, isTriangle(max, max, max)); // Handled by special case
- runTest("Max value isosceles (MAX, MAX, X)", true, isTriangle(max, max, maxHalf)); // Handled by special case
- runTest("Max value isosceles (base small)", true, isTriangle(max, max, 1)); // Handled by special case
- runTest("Max value scalene (near max, general check)", true, isTriangle(maxSlightlyLess, maxHalf, maxHalf + maxHalf / 2));
- runTest("Max value impossible (degenerate, near max)", false, isTriangle(maxHalf, maxHalf, max));
- runTest("Max value impossible (sum < third, near max)", false, isTriangle(maxHalf, maxHalf / 2, max));
- // THIS IS THE CRITICAL TEST THAT FAILED BEFORE: (MAX, 1, MAX) should be false
- runTest("Max value precision limit (a+c > b fails in simple check)", false, isTriangle(max, 1, max)); // Handled by general check now
- // 4.4 Non-Finite Inputs
- runTest("Infinity side (a=Infinity)", false, isTriangle(Infinity, 5, 5));
- runTest("Infinity side (b=Infinity)", false, isTriangle(5, Infinity, 5));
- runTest("Infinity side (c=Infinity)", false, isTriangle(5, 5, Infinity));
- runTest("Two Infinity sides", false, isTriangle(Infinity, Infinity, 5));
- runTest("All Infinity sides", false, isTriangle(Infinity, Infinity, Infinity));
- runTest("NaN side (a=NaN)", false, isTriangle(NaN, 5, 5));
- runTest("NaN side (b=NaN)", false, isTriangle(5, NaN, 5));
- runTest("NaN side (c=NaN)", false, isTriangle(5, 5, NaN));
- runTest("All NaN sides", false, isTriangle(NaN, NaN, NaN));
- // --- Test Summary ---
- console.log("\n--- Test Summary ---");
- console.log(`Total Tests: ${passed + failed}`);
- console.log(`Passed: ${passed}`);
- console.log(`Failed: ${failed}`);
- if (failed > 0) {
- console.error("\n❌ Some tests failed!");
- // process.exit(1); // Optional for Node.js
- } else {
- console.log("\n✅ All tests passed!");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement