FAILURE MAP
← Case archive

FA-16846 / Floating-point arithmetic / Open access

Atan2 identifies the negative real axis using ordinary comparison · case 01

Atan2 identifies the negative real axis using ordinary comparison.

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

ROOT CAUSE

Atan2 identifies the negative real axis using ordinary comparison. The faulty expression is math.pi if x<0 else 0.0.

VERIFIED REPAIR

Apply the contract at this fault site using math.pi if math.copysign(1.0,x)<0 else 0.0.

Unsuccessful approach: The attempted local correction math.pi if x<=0 else 0.0 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 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 origin03.1415926536Failed
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 / 1480e4301970b74bb332ebfa0d50e76cae71a6d60a498d22586ad535a7e6ebd1

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 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 origin3.14159265360Failed
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 / 44a7ccf8a431f1570b1d40c675602a2aff6c88d8d26521de0ff87c83b11e4a4b

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.416485+00:00.

Case digest / 924dec3591eec9d5bb0a1e22a3692f49059c2216559c98f91c81a324bd95b774