FAILURE MAP
← Case archive

FA-84351 / Betting odds conversion / Open access

Favourite moneyline computed with the underdog formula · case 01

A 1.50 price is shown as -50 instead of -200.

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

ROOT CAUSE

The favourite branch multiplies the profit by 100 instead of dividing 100 by it.

VERIFIED REPAIR

Use 100 / (d - 1) for prices below 2.

Unsuccessful approach: Dividing 100 by the whole decimal price confuses the moneyline with implied probability.

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 = Fraction(decimal)
    if d <= 1:
        return 'invalid'
    if d >= 2:
        v = (d - 1) * 100
        sign = '+'
    else:
        v = (d - 1) * 100
        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: favourite formula', ('1.393',), '-254'),
  ('variant scenario 1', ('2.638',), '+164'),
  ('variant scenario 2', ('6.44',), '+544')],
 [('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: favourite formula', ('1.600',), '-167'),
  ('variant scenario 1', ('2.82',), '+182'),
  ('variant scenario 2', ('5.11',), '+411')],
 [('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: favourite formula', ('1.13',), '-769'),
  ('variant scenario 1', ('2.98',), '+198'),
  ('variant scenario 2', ('6.10',), '+510')],
 [('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: favourite formula', ('1.64',), '-156'),
  ('variant scenario 1', ('13.76',), '+1276'),
  ('variant scenario 2', ('11.19',), '+1019')],
 [('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: favourite formula', ('1.108',), '-926'),
  ('variant scenario 1', ('4.59',), '+359'),
  ('variant scenario 2', ('5.05',), '+405')]]
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-50-200Failed
boundary evens+100+100Passed
boundary half-cent rounds up+101+101Passed
boundary no-profit priceinvalidinvalidPassed
control short favourite-8-1250Failed
regression: favourite formula-39-254Failed
variant scenario 1+164+164Passed
variant scenario 2+544+544Passed

SHA-256 / b34d392109fc4fe7f09dd78f4b64ec22bce85d0c66258b8da55844c6b4cb7ce0

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 = Fraction(decimal)
    if d <= 1:
        return 'invalid'
    if d >= 2:
        v = (d - 1) * 100
        sign = '+'
    else:
        v = 100 / d
        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: favourite formula', ('1.393',), '-254'),
  ('variant scenario 1', ('2.638',), '+164'),
  ('variant scenario 2', ('6.44',), '+544')],
 [('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: favourite formula', ('1.600',), '-167'),
  ('variant scenario 1', ('2.82',), '+182'),
  ('variant scenario 2', ('5.11',), '+411')],
 [('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: favourite formula', ('1.13',), '-769'),
  ('variant scenario 1', ('2.98',), '+198'),
  ('variant scenario 2', ('6.10',), '+510')],
 [('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: favourite formula', ('1.64',), '-156'),
  ('variant scenario 1', ('13.76',), '+1276'),
  ('variant scenario 2', ('11.19',), '+1019')],
 [('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: favourite formula', ('1.108',), '-926'),
  ('variant scenario 1', ('4.59',), '+359'),
  ('variant scenario 2', ('5.05',), '+405')]]
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-67-200Failed
boundary evens+100+100Passed
boundary half-cent rounds up+101+101Passed
boundary no-profit priceinvalidinvalidPassed
control short favourite-93-1250Failed
regression: favourite formula-72-254Failed
variant scenario 1+164+164Passed
variant scenario 2+544+544Passed

SHA-256 / c29fb3040fc99c8a108f05a1c611533aac8d8ed6a4c433ecce0f18c3d65605ae

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: favourite formula', ('1.393',), '-254'),
  ('variant scenario 1', ('2.638',), '+164'),
  ('variant scenario 2', ('6.44',), '+544')],
 [('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: favourite formula', ('1.600',), '-167'),
  ('variant scenario 1', ('2.82',), '+182'),
  ('variant scenario 2', ('5.11',), '+411')],
 [('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: favourite formula', ('1.13',), '-769'),
  ('variant scenario 1', ('2.98',), '+198'),
  ('variant scenario 2', ('6.10',), '+510')],
 [('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: favourite formula', ('1.64',), '-156'),
  ('variant scenario 1', ('13.76',), '+1276'),
  ('variant scenario 2', ('11.19',), '+1019')],
 [('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: favourite formula', ('1.108',), '-926'),
  ('variant scenario 1', ('4.59',), '+359'),
  ('variant scenario 2', ('5.05',), '+405')]]
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: favourite formula-254-254Passed
variant scenario 1+164+164Passed
variant scenario 2+544+544Passed

SHA-256 / 09db47a6e94e56ad5dcb1ac33ff3941ae1bb870ba37ad16ecf6ca5ecbd8be47f

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

Case digest / 9299d08cee3ca80a78f5b6071641dcb32541b1dbe940a687070fa6c5d4fccde2