FAILURE MAP
← Case archive

FA-16861 / Floating-point arithmetic / Open access

Atan2 fails to complement its steep-slope ratio · case 01

Atan2 fails to complement its steep-slope ratio.

Verified by executionVariant 1 · 16 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Atan2 fails to complement its steep-slope ratio. The faulty expression is else: angle=math.atan(a/b).

VERIFIED REPAIR

Apply the contract at this fault site using else: angle=math.pi/2-math.atan(a/b).

Unsuccessful approach: The attempted local correction else: angle=math.pi-math.atan(a/b) still violates the explicit regression fixtures.

Case contract

Evaluate atan2(y,x) including signed zero and infinite directions; NaN produces nan. Finite nonzero coordinates use ratio of smaller magnitude and quadrant reconstruction. Finite results are rendered to eleven significant decimal digits; modeled domain violations and arithmetic errors are explicit strings.

Why this case matters

An offline floating representation model isolates a reproducible arithmetic fault.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
import struct
def render(x):
    if math.isnan(x): return 'nan'
    if math.isinf(x): return '-infinity' if x<0 else '+infinity'
    return format(x,'.11g')

N = 1
observations = []
def solve(y,x):
    try:
        if math.isnan(x) or math.isnan(y): return 'nan'
        if math.isinf(x) and math.isinf(y):
            angle=math.pi/4 if x>0 else 3*math.pi/4
            return render(math.copysign(angle,y))
        if y==0:
            return render(math.copysign(math.pi if math.copysign(1.0,x)<0 else 0.0,y))
        if x==0: return render(math.copysign(math.pi/2,y))
        a=abs(x); b=abs(y)
        if b<=a: angle=math.atan(b/a)
        else: angle=math.atan(a/b)
        if x<0: angle=math.pi-angle
        return render(math.copysign(angle,y))
    except (ValueError, OverflowError, ZeroDivisionError, TypeError):
        return "arithmetic-error"
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('positive zero axis', solve(0.0,float(N)), "0")
check('negative zero axis', solve(-0.0,float(N)), "-0")
check('branch above', solve(0.0,-float(N)), render(math.pi))
check('branch below', solve(-0.0,-float(N)), render(-math.pi))
check('positive origin', solve(0.0,0.0), "0")
check('positive vertical', solve(float(N),0.0), render(math.pi/2))
check('steep slope', solve(10.0*N,1.0), render(math.atan2(10*N,1)))
check('signed origin', solve(0.0,-0.0), render(math.pi))
check('vertical negative', solve(-float(N),0.0), render(-math.pi/2))
check('quadrant one', solve(float(N),2.0), render(math.atan2(N,2)))
check('quadrant two', solve(float(N),-2.0), render(math.atan2(N,-2)))
check('quadrant three', solve(-float(N),-2.0), render(math.atan2(-N,-2)))
check('tiny slope', solve(N*1e-300,1e300), "0")
check('both infinite', solve(math.inf,math.inf), render(math.pi/4))
check('negative infinite', solve(-math.inf,-math.inf), render(-3*math.pi/4))
check('nan coordinate', solve(float("nan"),float(N)), "nan")
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
positive zero axis00Passed
negative zero axis-0-0Passed
branch above3.14159265363.1415926536Passed
branch below-3.1415926536-3.1415926536Passed
positive origin00Passed
positive vertical1.57079632681.5707963268Passed
steep slope0.0996686524911.4711276743Failed
signed origin3.14159265363.1415926536Passed
vertical negative-1.5707963268-1.5707963268Passed
quadrant one0.4636476090.463647609Passed
quadrant two2.67794504462.6779450446Passed
quadrant three-2.6779450446-2.6779450446Passed
tiny slope00Passed
both infinite0.78539816340.7853981634Passed
negative infinite-2.3561944902-2.3561944902Passed
nan coordinatenannanPassed

SHA-256 / 71e1f9c3f314212e9cee8114280118377a2495001cf1ef8f4d5bce6de47d56bf

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
import struct
def render(x):
    if math.isnan(x): return 'nan'
    if math.isinf(x): return '-infinity' if x<0 else '+infinity'
    return format(x,'.11g')

N = 1
observations = []
def solve(y,x):
    try:
        if math.isnan(x) or math.isnan(y): return 'nan'
        if math.isinf(x) and math.isinf(y):
            angle=math.pi/4 if x>0 else 3*math.pi/4
            return render(math.copysign(angle,y))
        if y==0:
            return render(math.copysign(math.pi if math.copysign(1.0,x)<0 else 0.0,y))
        if x==0: return render(math.copysign(math.pi/2,y))
        a=abs(x); b=abs(y)
        if b<=a: angle=math.atan(b/a)
        else: angle=math.pi-math.atan(a/b)
        if x<0: angle=math.pi-angle
        return render(math.copysign(angle,y))
    except (ValueError, OverflowError, ZeroDivisionError, TypeError):
        return "arithmetic-error"
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('positive zero axis', solve(0.0,float(N)), "0")
check('negative zero axis', solve(-0.0,float(N)), "-0")
check('branch above', solve(0.0,-float(N)), render(math.pi))
check('branch below', solve(-0.0,-float(N)), render(-math.pi))
check('positive origin', solve(0.0,0.0), "0")
check('positive vertical', solve(float(N),0.0), render(math.pi/2))
check('steep slope', solve(10.0*N,1.0), render(math.atan2(10*N,1)))
check('signed origin', solve(0.0,-0.0), render(math.pi))
check('vertical negative', solve(-float(N),0.0), render(-math.pi/2))
check('quadrant one', solve(float(N),2.0), render(math.atan2(N,2)))
check('quadrant two', solve(float(N),-2.0), render(math.atan2(N,-2)))
check('quadrant three', solve(-float(N),-2.0), render(math.atan2(-N,-2)))
check('tiny slope', solve(N*1e-300,1e300), "0")
check('both infinite', solve(math.inf,math.inf), render(math.pi/4))
check('negative infinite', solve(-math.inf,-math.inf), render(-3*math.pi/4))
check('nan coordinate', solve(float("nan"),float(N)), "nan")
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
positive zero axis00Passed
negative zero axis-0-0Passed
branch above3.14159265363.1415926536Passed
branch below-3.1415926536-3.1415926536Passed
positive origin00Passed
positive vertical1.57079632681.5707963268Passed
steep slope3.04192400111.4711276743Failed
signed origin3.14159265363.1415926536Passed
vertical negative-1.5707963268-1.5707963268Passed
quadrant one0.4636476090.463647609Passed
quadrant two2.67794504462.6779450446Passed
quadrant three-2.6779450446-2.6779450446Passed
tiny slope00Passed
both infinite0.78539816340.7853981634Passed
negative infinite-2.3561944902-2.3561944902Passed
nan coordinatenannanPassed

SHA-256 / d9060dc779ffdd26dd3d4cff8238975da9a6448d7b28960fadfc6e2bea0d64a8

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
import struct
def render(x):
    if math.isnan(x): return 'nan'
    if math.isinf(x): return '-infinity' if x<0 else '+infinity'
    return format(x,'.11g')

N = 1
observations = []
def solve(y,x):
    try:
        if math.isnan(x) or math.isnan(y): return 'nan'
        if math.isinf(x) and math.isinf(y):
            angle=math.pi/4 if x>0 else 3*math.pi/4
            return render(math.copysign(angle,y))
        if y==0:
            return render(math.copysign(math.pi if math.copysign(1.0,x)<0 else 0.0,y))
        if x==0: return render(math.copysign(math.pi/2,y))
        a=abs(x); b=abs(y)
        if b<=a: angle=math.atan(b/a)
        else: angle=math.pi/2-math.atan(a/b)
        if x<0: angle=math.pi-angle
        return render(math.copysign(angle,y))
    except (ValueError, OverflowError, ZeroDivisionError, TypeError):
        return "arithmetic-error"
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('positive zero axis', solve(0.0,float(N)), "0")
check('negative zero axis', solve(-0.0,float(N)), "-0")
check('branch above', solve(0.0,-float(N)), render(math.pi))
check('branch below', solve(-0.0,-float(N)), render(-math.pi))
check('positive origin', solve(0.0,0.0), "0")
check('positive vertical', solve(float(N),0.0), render(math.pi/2))
check('steep slope', solve(10.0*N,1.0), render(math.atan2(10*N,1)))
check('signed origin', solve(0.0,-0.0), render(math.pi))
check('vertical negative', solve(-float(N),0.0), render(-math.pi/2))
check('quadrant one', solve(float(N),2.0), render(math.atan2(N,2)))
check('quadrant two', solve(float(N),-2.0), render(math.atan2(N,-2)))
check('quadrant three', solve(-float(N),-2.0), render(math.atan2(-N,-2)))
check('tiny slope', solve(N*1e-300,1e300), "0")
check('both infinite', solve(math.inf,math.inf), render(math.pi/4))
check('negative infinite', solve(-math.inf,-math.inf), render(-3*math.pi/4))
check('nan coordinate', solve(float("nan"),float(N)), "nan")
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
positive zero axis00Passed
negative zero axis-0-0Passed
branch above3.14159265363.1415926536Passed
branch below-3.1415926536-3.1415926536Passed
positive origin00Passed
positive vertical1.57079632681.5707963268Passed
steep slope1.47112767431.4711276743Passed
signed origin3.14159265363.1415926536Passed
vertical negative-1.5707963268-1.5707963268Passed
quadrant one0.4636476090.463647609Passed
quadrant two2.67794504462.6779450446Passed
quadrant three-2.6779450446-2.6779450446Passed
tiny slope00Passed
both infinite0.78539816340.7853981634Passed
negative infinite-2.3561944902-2.3561944902Passed
nan coordinatenannanPassed

SHA-256 / f929e4baf91e56cf334bd90146c05b96a4ac1227a21cea2c3278c0336055dc75

Verification & scope

Controlled binary64 or explicitly stipulated miniature format; no hardware exception flags or platform floating environment are modeled. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:39:40.607240+00:00.

Case digest / 3223be30b6141f794daa03128a5f9f5f0683df65cd307bd0e857c69009895a83