FA-84406 / Betting odds conversion / Open access
Fractional-to-decimal conversion rounds half-cents down · case 01
"1/8" is shown as 1.12 instead of 1.13.
ROOT CAUSE
The decimal is formatted from a binary float with '%.2f'.
VERIFIED REPAIR
Round the exact decimal half up.
Unsuccessful approach: Truncating the exact value shows 2/3 as 1.66.
Case contract
Parse traditional fractional odds text, case-insensitively: "a/b" or "a-b" with positive integers, "evens"/"evs"/"even" for 1/1, and an optional trailing " on" meaning odds-on (the fraction is inverted, "2/1 on" = 1/2). Zero parts or anything else return "invalid". Return [decimal price rounded half up to two decimals, reduced profit fraction "a/b"].
Why this case matters
Racing feeds and manual price entry use traditional fractional notation with odds-on suffixes.
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(text):
t = text.strip().lower()
on = t.endswith(' on')
if on:
t = t[:-3].strip()
if t in ('evens', 'evs', 'even'):
frac = Fraction(1)
else:
for sep in ('/', '-'):
if sep in t:
a, _, b = t.partition(sep)
break
else:
return 'invalid'
if not a.isdigit() or not b.isdigit() or int(b) == 0 or int(a) == 0:
return 'invalid'
frac = Fraction(int(a), int(b))
if on:
frac = 1 / frac
dec = 1 + frac
cents = math.floor(dec * 100 + Fraction(1, 2))
return ['%.2f' % float(dec), '%d/%d' % (frac.numerator, frac.denominator)]
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 five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('14/13',), ['2.08', '14/13']),
('regression: decimal half up', ('1/8',), ['1.13', '1/8']),
('variant scenario 1', ('4-1',), ['5.00', '4/1']),
('variant scenario 2', ('11/2',), ['6.50', '11/2'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('7/13',), ['1.54', '7/13']),
('regression: decimal half up', ('9/8',), ['2.13', '9/8']),
('variant scenario 1', ('15-4',), ['4.75', '15/4']),
('variant scenario 2', ('4-8 on',), ['3.00', '2/1'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('18/11',), ['2.64', '18/11']),
('regression: decimal half up', ('1/8',), ['1.13', '1/8']),
('variant scenario 1', ('19/13',), ['2.46', '19/13']),
('variant scenario 2', ('6/10',), ['1.60', '3/5'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('7/13',), ['1.54', '7/13']),
('regression: decimal half up', ('8/13 on',), ['2.63', '13/8']),
('variant scenario 1', ('5-2',), ['3.50', '5/2']),
('variant scenario 2', ('12-10',), ['2.20', '6/5'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('10-13',), ['1.77', '10/13']),
('regression: decimal half up', ('13-8',), ['2.63', '13/8']),
('variant scenario 1', ('EVS',), ['2.00', '1/1']),
('variant scenario 2', ('8/2',), ['5.00', '4/1'])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| control five to two | ['3.50', '5/2'] | ['3.50', '5/2'] | Passed |
| control hyphen separator | ['3.75', '11/4'] | ['3.75', '11/4'] | Passed |
| boundary evens alias | ['2.00', '1/1'] | ['2.00', '1/1'] | Passed |
| boundary odds-on suffix | ['1.50', '1/2'] | ['1.50', '1/2'] | Passed |
| boundary unreduced input | ['1.67', '2/3'] | ['1.67', '2/3'] | Passed |
| boundary zero denominator | invalid | invalid | Passed |
| control half-up rounding | ['1.12', '1/8'] | ['1.13', '1/8'] | Failed |
| regression: decimal half up | ['2.08', '14/13'] | ['2.08', '14/13'] | Passed |
| regression: decimal half up | ['1.12', '1/8'] | ['1.13', '1/8'] | Failed |
| variant scenario 1 | ['5.00', '4/1'] | ['5.00', '4/1'] | Passed |
| variant scenario 2 | ['6.50', '11/2'] | ['6.50', '11/2'] | Passed |
SHA-256 / 92de2746ce9190e2cfafb1fe5e0194b763ad4e646e5f697c9c7813d9ba33358e
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(text):
t = text.strip().lower()
on = t.endswith(' on')
if on:
t = t[:-3].strip()
if t in ('evens', 'evs', 'even'):
frac = Fraction(1)
else:
for sep in ('/', '-'):
if sep in t:
a, _, b = t.partition(sep)
break
else:
return 'invalid'
if not a.isdigit() or not b.isdigit() or int(b) == 0 or int(a) == 0:
return 'invalid'
frac = Fraction(int(a), int(b))
if on:
frac = 1 / frac
dec = 1 + frac
cents = math.floor(dec * 100)
return ['%d.%02d' % (cents // 100, cents % 100), '%d/%d' % (frac.numerator, frac.denominator)]
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 five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('14/13',), ['2.08', '14/13']),
('regression: decimal half up', ('1/8',), ['1.13', '1/8']),
('variant scenario 1', ('4-1',), ['5.00', '4/1']),
('variant scenario 2', ('11/2',), ['6.50', '11/2'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('7/13',), ['1.54', '7/13']),
('regression: decimal half up', ('9/8',), ['2.13', '9/8']),
('variant scenario 1', ('15-4',), ['4.75', '15/4']),
('variant scenario 2', ('4-8 on',), ['3.00', '2/1'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('18/11',), ['2.64', '18/11']),
('regression: decimal half up', ('1/8',), ['1.13', '1/8']),
('variant scenario 1', ('19/13',), ['2.46', '19/13']),
('variant scenario 2', ('6/10',), ['1.60', '3/5'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('7/13',), ['1.54', '7/13']),
('regression: decimal half up', ('8/13 on',), ['2.63', '13/8']),
('variant scenario 1', ('5-2',), ['3.50', '5/2']),
('variant scenario 2', ('12-10',), ['2.20', '6/5'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('10-13',), ['1.77', '10/13']),
('regression: decimal half up', ('13-8',), ['2.63', '13/8']),
('variant scenario 1', ('EVS',), ['2.00', '1/1']),
('variant scenario 2', ('8/2',), ['5.00', '4/1'])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| control five to two | ['3.50', '5/2'] | ['3.50', '5/2'] | Passed |
| control hyphen separator | ['3.75', '11/4'] | ['3.75', '11/4'] | Passed |
| boundary evens alias | ['2.00', '1/1'] | ['2.00', '1/1'] | Passed |
| boundary odds-on suffix | ['1.50', '1/2'] | ['1.50', '1/2'] | Passed |
| boundary unreduced input | ['1.66', '2/3'] | ['1.67', '2/3'] | Failed |
| boundary zero denominator | invalid | invalid | Passed |
| control half-up rounding | ['1.12', '1/8'] | ['1.13', '1/8'] | Failed |
| regression: decimal half up | ['2.07', '14/13'] | ['2.08', '14/13'] | Failed |
| regression: decimal half up | ['1.12', '1/8'] | ['1.13', '1/8'] | Failed |
| variant scenario 1 | ['5.00', '4/1'] | ['5.00', '4/1'] | Passed |
| variant scenario 2 | ['6.50', '11/2'] | ['6.50', '11/2'] | Passed |
SHA-256 / 181b1bb7a102b7001eaa1b3274ed54dd9c0a472b144a6e882a15c2568a1012f5
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(text):
t = text.strip().lower()
on = t.endswith(' on')
if on:
t = t[:-3].strip()
if t in ('evens', 'evs', 'even'):
frac = Fraction(1)
else:
for sep in ('/', '-'):
if sep in t:
a, _, b = t.partition(sep)
break
else:
return 'invalid'
if not a.isdigit() or not b.isdigit() or int(b) == 0 or int(a) == 0:
return 'invalid'
frac = Fraction(int(a), int(b))
if on:
frac = 1 / frac
dec = 1 + frac
cents = math.floor(dec * 100 + Fraction(1, 2))
return ['%d.%02d' % (cents // 100, cents % 100), '%d/%d' % (frac.numerator, frac.denominator)]
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 five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('14/13',), ['2.08', '14/13']),
('regression: decimal half up', ('1/8',), ['1.13', '1/8']),
('variant scenario 1', ('4-1',), ['5.00', '4/1']),
('variant scenario 2', ('11/2',), ['6.50', '11/2'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('7/13',), ['1.54', '7/13']),
('regression: decimal half up', ('9/8',), ['2.13', '9/8']),
('variant scenario 1', ('15-4',), ['4.75', '15/4']),
('variant scenario 2', ('4-8 on',), ['3.00', '2/1'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('18/11',), ['2.64', '18/11']),
('regression: decimal half up', ('1/8',), ['1.13', '1/8']),
('variant scenario 1', ('19/13',), ['2.46', '19/13']),
('variant scenario 2', ('6/10',), ['1.60', '3/5'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('7/13',), ['1.54', '7/13']),
('regression: decimal half up', ('8/13 on',), ['2.63', '13/8']),
('variant scenario 1', ('5-2',), ['3.50', '5/2']),
('variant scenario 2', ('12-10',), ['2.20', '6/5'])],
[('control five to two', ('5/2',), ['3.50', '5/2']),
('control hyphen separator', ('11-4',), ['3.75', '11/4']),
('boundary evens alias', ('EVS',), ['2.00', '1/1']),
('boundary odds-on suffix', ('2/1 on',), ['1.50', '1/2']),
('boundary unreduced input', ('4/6',), ['1.67', '2/3']),
('boundary zero denominator', ('5/0',), 'invalid'),
('control half-up rounding', ('1/8',), ['1.13', '1/8']),
('regression: decimal half up', ('10-13',), ['1.77', '10/13']),
('regression: decimal half up', ('13-8',), ['2.63', '13/8']),
('variant scenario 1', ('EVS',), ['2.00', '1/1']),
('variant scenario 2', ('8/2',), ['5.00', '4/1'])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| control five to two | ['3.50', '5/2'] | ['3.50', '5/2'] | Passed |
| control hyphen separator | ['3.75', '11/4'] | ['3.75', '11/4'] | Passed |
| boundary evens alias | ['2.00', '1/1'] | ['2.00', '1/1'] | Passed |
| boundary odds-on suffix | ['1.50', '1/2'] | ['1.50', '1/2'] | Passed |
| boundary unreduced input | ['1.67', '2/3'] | ['1.67', '2/3'] | Passed |
| boundary zero denominator | invalid | invalid | Passed |
| control half-up rounding | ['1.13', '1/8'] | ['1.13', '1/8'] | Passed |
| regression: decimal half up | ['2.08', '14/13'] | ['2.08', '14/13'] | Passed |
| regression: decimal half up | ['1.13', '1/8'] | ['1.13', '1/8'] | Passed |
| variant scenario 1 | ['5.00', '4/1'] | ['5.00', '4/1'] | Passed |
| variant scenario 2 | ['6.50', '11/2'] | ['6.50', '11/2'] | Passed |
SHA-256 / 7489cc49a0f7e81e85c2a033af6077c72117fd6d17749ac5881e10dcfc893089
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.523149+00:00.
Case digest / e56c614fb2efa20ed7f16d1d3a96ab610565d383e68266c89338ab340f101b07