FAILURE MAP
← Case archive

FA-84361 / Betting odds conversion / Open access

Decimal price parsed as a binary float · case 01

Prices exactly on a half-dollar boundary round the wrong way.

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

ROOT CAUSE

The price text is parsed with float(), so 2.005 becomes 2.00499999...

VERIFIED REPAIR

Parse the decimal text exactly.

Unsuccessful approach: Rounding the float to two decimals first cannot restore the lost half-cent.

Case contract

Convert a decimal price string to an American moneyline string. Prices at or below 1 return "invalid". For d >= 2 the line is "+" followed by 100 * (d - 1); for d < 2 it is "-" followed by 100 / (d - 1). The magnitude is computed exactly from the decimal text and rounded half up to an integer. Evens (2.00) is "+100".

Why this case matters

Sportsbooks display the same price in decimal and American formats and must agree at every boundary.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(decimal):
    d = float(decimal)
    if d <= 1:
        return 'invalid'
    if d >= 2:
        v = (d - 1) * 100
        sign = '+'
    else:
        v = 100 / (d - 1)
        sign = '-'
    n = math.floor(v + Fraction(1, 2))
    return sign + str(n)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
def run(args):
    try:
        return solve(*args)
    except Exception as exc:
        return 'raised ' + type(exc).__name__
cases = [[('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('6.99',), '+599'),
  ('variant scenario 2', ('2.75',), '+175')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('3.125',), '+213'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('2.951',), '+195'),
  ('variant scenario 2', ('6.21',), '+521')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('14.74',), '+1374'),
  ('variant scenario 2', ('1.00',), 'invalid')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('3.125',), '+213'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('13.57',), '+1257'),
  ('variant scenario 2', ('10.35',), '+935')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('2.125',), '+113'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('5.20',), '+420'),
  ('variant scenario 2', ('8.76',), '+776')]]
for label, args, expected in cases[N - 1]:
    check(label, run(args), expected)
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
control underdog+150+150Passed
control favourite-200-200Passed
boundary evens+100+100Passed
boundary half-cent rounds up+100+101Failed
boundary no-profit priceinvalidinvalidPassed
control short favourite-1250-1250Passed
regression: binary float parse+100+101Failed
variant scenario 1+599+599Passed
variant scenario 2+175+175Passed

SHA-256 / b31c01fef78bc73cef39ebf9a26864516bb67143ef214d623ef075971c24fae2

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(decimal):
    d = round(float(decimal), 2)
    if d <= 1:
        return 'invalid'
    if d >= 2:
        v = (d - 1) * 100
        sign = '+'
    else:
        v = 100 / (d - 1)
        sign = '-'
    n = math.floor(v + Fraction(1, 2))
    return sign + str(n)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
def run(args):
    try:
        return solve(*args)
    except Exception as exc:
        return 'raised ' + type(exc).__name__
cases = [[('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('6.99',), '+599'),
  ('variant scenario 2', ('2.75',), '+175')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('3.125',), '+213'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('2.951',), '+195'),
  ('variant scenario 2', ('6.21',), '+521')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('14.74',), '+1374'),
  ('variant scenario 2', ('1.00',), 'invalid')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('3.125',), '+213'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('13.57',), '+1257'),
  ('variant scenario 2', ('10.35',), '+935')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('2.125',), '+113'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('5.20',), '+420'),
  ('variant scenario 2', ('8.76',), '+776')]]
for label, args, expected in cases[N - 1]:
    check(label, run(args), expected)
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
control underdog+150+150Passed
control favourite-200-200Passed
boundary evens+100+100Passed
boundary half-cent rounds up+100+101Failed
boundary no-profit priceinvalidinvalidPassed
control short favourite-1250-1250Passed
regression: binary float parse+100+101Failed
variant scenario 1+599+599Passed
variant scenario 2+175+175Passed

SHA-256 / f8183c77a081d4e7fd75c8344e9a476baf3020d6683cf57380bcef785044a852

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(decimal):
    d = Fraction(decimal)
    if d <= 1:
        return 'invalid'
    if d >= 2:
        v = (d - 1) * 100
        sign = '+'
    else:
        v = 100 / (d - 1)
        sign = '-'
    n = math.floor(v + Fraction(1, 2))
    return sign + str(n)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
def run(args):
    try:
        return solve(*args)
    except Exception as exc:
        return 'raised ' + type(exc).__name__
cases = [[('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('6.99',), '+599'),
  ('variant scenario 2', ('2.75',), '+175')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('3.125',), '+213'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('2.951',), '+195'),
  ('variant scenario 2', ('6.21',), '+521')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('14.74',), '+1374'),
  ('variant scenario 2', ('1.00',), 'invalid')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('3.125',), '+213'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('13.57',), '+1257'),
  ('variant scenario 2', ('10.35',), '+935')],
 [('control underdog', ('2.50',), '+150'),
  ('control favourite', ('1.50',), '-200'),
  ('boundary evens', ('2.00',), '+100'),
  ('boundary half-cent rounds up', ('2.005',), '+101'),
  ('boundary no-profit price', ('1.00',), 'invalid'),
  ('control short favourite', ('1.08',), '-1250'),
  ('regression: binary float parse', ('2.125',), '+113'),
  ('regression: binary float parse', ('2.005',), '+101'),
  ('variant scenario 1', ('5.20',), '+420'),
  ('variant scenario 2', ('8.76',), '+776')]]
for label, args, expected in cases[N - 1]:
    check(label, run(args), expected)
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
control underdog+150+150Passed
control favourite-200-200Passed
boundary evens+100+100Passed
boundary half-cent rounds up+101+101Passed
boundary no-profit priceinvalidinvalidPassed
control short favourite-1250-1250Passed
regression: binary float parse+101+101Passed
variant scenario 1+599+599Passed
variant scenario 2+175+175Passed

SHA-256 / 3e139fafbf41b39ce97902fed96b941bfcbcd840739da14b3975a7969d1ec61e

Verification & scope

Stipulated, bounded toy contract stated in the contract field; not a claim of conformance with any operator, exchange or regulator rule set. 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:50:30.248740+00:00.

Case digest / eebb1c87e2088c44b4e10e950efd6e3a27485ae435b508b004d62417ed39b062