24
\$\begingroup\$

American odds (aka moneyline odds) are numbers like \$+150\$ or \$-400\$ used to express how much a winning bet would pay out. Convert odds to a fair win probability like this:

  • Positive odds \$+n\$ with \$n \geq 100\$ correspond to $$p=\frac{100}{100+n},$$ producing a probability with \$0 < p \leq 1/2\$.
  • Negative odds \$-n\$ with \$n > 100\$ correspond to $$p=\frac{n}{100+n},$$ producing a probability with \$1/2 < p < 1\$.

Note that in both formulas above, \$n\$ is the absolute value of the input. Inputs with absolute value under \$100\$ are invalid, and so is \$-100\$ (since \$+100\$ is used for \$p=1/2\$), so you don't need to handle these.

The input will be a whole number. If you take it as a string, expecting a leading + for positive values is optional.

Your output can be a decimal to some reasonable precision or a reduced fraction.

Test cases

+1500   0.0625
 +256   0.2808988764044944
 +100   0.5
 -200   0.6666666666666666
 -300   0.75
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Can the input be 0? \$\endgroup\$ Commented Sep 12, 2023 at 17:54
  • 3
    \$\begingroup\$ @noodleman No, the input is always \$>=100\$ or \$<-100\$. \$\endgroup\$
    – xnor
    Commented Sep 12, 2023 at 17:54
  • 8
    \$\begingroup\$ Why do Americans have to use weird units for everything? \$\endgroup\$
    – Trang Oul
    Commented Sep 14, 2023 at 12:25
  • 4
    \$\begingroup\$ @TrangOul As an American, it seemed strange to me, too. But looking deeper, I found it explained in a way that made more sense: negative moneyline odds represent the amount of money you need to wager to have a chance of winning $100; positive odds represent the amount of money you could win if you wager $100. This has the nice property that the opposite odds are inverses. 1-to-10 odds are \$-1000\$ , while 10-to-1 odds are \$+1000\$ . \$\endgroup\$ Commented Sep 15, 2023 at 14:58

23 Answers 23

26
\$\begingroup\$

Python, 25 bytes

lambda x:x/(~99-abs(x))%1

Attempt This Online!

Thanks @Jonathan Allan for -1.

Original Python, 26 bytes

lambda x:-x/(100+abs(x))%1

Attempt This Online!

Test bed from @MTN via @AnttiP.

How?

Based on the observation

\$-n \equiv 100 \mod 100+n\$

\$\endgroup\$
0
12
\$\begingroup\$

Jelly, 7 bytes

,³ṢAÄ÷/

Try it online!

Function I/O only because lmao ³. (Replace with ȷ2 if that's too borderline.)

                                  n ≥ 100         | n < -100
,³         Pair n with 100.       [n, 100]        | [n, 100]
  Ṣ        Sort.                  [100, n]        | [n, 100]
   A       Map absolute value.    [100, n]        | [-n, 100]
    Ä      Cumsum.                [100, 100 + n]  | [-n, 100 - n]
     ÷/    Divide.                100 / (100 + n) | -n / (100 - n)
\$\endgroup\$
7
\$\begingroup\$

R, 24 bytes

\(n)(-n/(100+abs(n)))%%1

Attempt This Online!

Port of loopy walt's Python answer.

\$\endgroup\$
6
\$\begingroup\$

Python, 33 bytes

lambda n:1/[1+n/100,1-100/n][n<0]

Attempt This Online!

Testing code from MTN's answer

\$\endgroup\$
0
5
\$\begingroup\$

Ruby, 29 26 bytes

->n{(n>0?100:n=-n)/n+=1e2}

Attempt This Online!

Saved 3 bytes thanks to @MTN and @G B.

Ports Luis felipe De jesus Munoz’s JavaScript submission.

Ruby, 34 28 bytes

->n{[-n,o=1e2].max/o+=n.abs}

Attempt This Online!

Thanks to @G B for saving 8 bytes!

I'm still learning Ruby, so this answer might be improvable, although @G B has improved it quite a bit already.

\$\endgroup\$
7
  • \$\begingroup\$ 27 bytes \$\endgroup\$
    – MTN
    Commented Sep 12, 2023 at 18:41
  • \$\begingroup\$ @MTN What?? Why is 1e2 a float? Thanks for showing me something weird lol \$\endgroup\$ Commented Sep 12, 2023 at 22:42
  • \$\begingroup\$ 26 bytes by using n+=1e2 instead of (1e2+n) \$\endgroup\$
    – G B
    Commented Sep 13, 2023 at 15:07
  • \$\begingroup\$ Also your original post can be shortened to 28: ->n{[-n,o=1e2].max/o+=n.abs} \$\endgroup\$
    – G B
    Commented Sep 13, 2023 at 15:16
  • \$\begingroup\$ @noodleman I can't think of a language where a literal expressed in scientific notation isn't a float \$\endgroup\$
    – c--
    Commented Sep 13, 2023 at 16:10
4
\$\begingroup\$

Vyxal, 55 bitsv2, 6.875 bytes

₁"sȧ¦ƒ/

Try it Online!

Port of Jelly.

\$\endgroup\$
4
\$\begingroup\$

Vyxal, 50 bitsv2, 6.25 bytes

ȧ₁+/N1%

Try it Online!

Port of loopy walt's Python. It's longer in Jelly due to the argument order for division, but I intuited it would at least tie in Vyxal SBCS bytes, and it turns out it also Vyncodes marginally better.

 ₁+        Add 100 to
ȧ          the absolute value of n.
   /       Divide n by that,
    N      negate the result,
     1%    and mod 1.
\$\endgroup\$
4
\$\begingroup\$

Pip, 12 bytes

-a/(h+ABa)%1

Attempt This Online! | Based on @loopy_walt's Python answer

Trivial implementation, 16 bytes.

(@YABSNgAEh)/$+y

Attempt This Online!

\$\endgroup\$
3
\$\begingroup\$

JavaScript (Babel Node), 25 bytes

_=>(_>0?100:_=-_)/(100+_)

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Excel, 30 bytes

=1/(1+IF(A1<0,-100/A1,A1/100))

Input in cell A1.

\$\endgroup\$
3
\$\begingroup\$

Arturo, 34 bytes

$->n[abs//(n<0)?->n[100]100+abs n]

Try it!

\$\endgroup\$
3
\$\begingroup\$

R, 31 bytes

\(n)"if"(n<0,n<--n,100)/(100+n)

Attempt This Online!

R, 31 bytes

\(n,z=sign(n))1/(1+(n/100)^z*z)

Attempt This Online!

I feel like one of these can be golfed down.

\$\endgroup\$
3
\$\begingroup\$

J, 9 bytes

1|-%100+|

-5 bytes by porting loopy walt's answer!

Attempt This Online!

J, original answer, 14 bytes

(100>.-)%100+|

Attempt This Online!

  • 100>.- The larger of the negative of the input and 100
  • % Divided by...
  • 100+| 100 plus the absolute value of the input

My attempts to avoid repeating 100 led to longer solutions.

\$\endgroup\$
3
\$\begingroup\$

Forth (gforth), 51 42 bytes

: f dup 100 min abs s>f abs 100 + s>f f/ ;

Try it online!

Explanation

Originally, I used a conditional statement, but those use a lot of characters in gforth. I eventually realized that the goal is mostly just to determine what goes on top of the fraction, 100 or n. Since n will always be greater than 100 or less than -100, we can use min to get the value we want (if negative, n will always be less than 100, if positive, 100 will always be smaller).

Code Explanation

: f         \ Begin word definition
  dup       \ duplicate n on the top of the stack
  100 min   \ take the smaller of n and 100
  abs s>f   \ send the absolute value to the floating point stack
  abs 100 + \ add 100 to the absolute value of n
  s>f       \ move the result to the floating point stack
  f/        \ divide the top two floating point stack values
;           \ end word definition
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Another rediscovery of @noodleman's original Ruby answer. \$\endgroup\$
    – Neil
    Commented Sep 13, 2023 at 20:55
3
\$\begingroup\$

Julia, 29 24 bytes

!n=mod(n/(~99-abs(n)),1)

Attempt This Online!

A port of loopy walt's solution.

mod is used (suggested by MarcMush), since Julia's default modulo % doesn't match Python's convention for negative numbers; using rem with rounding mode RoundDown would also work.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ I think mod would work instead of %|rem ? \$\endgroup\$
    – MarcMush
    Commented Sep 15, 2023 at 21:58
2
\$\begingroup\$

Python, 37 bytes

lambda n:(100,x:=abs(n))[n<0]/(100+x)

Attempt This Online!

\$\endgroup\$
2
\$\begingroup\$

Octave / MATLAB, 30 bytes

@(n)min(100,n)/(n+100*sign(n))

Try it online! Or verify all test cases.

\$\endgroup\$
2
\$\begingroup\$

05AB1E (legacy), 7 bytes

Äт+/(1%

Port of @loopyWalt's Python answer, so make sure to upvote that answer as well!

Try it online or verify all test cases.

A port of @UnrelatedString's Jelly answer (in the new 05AB1E version) would be a byte longer:

т‚{ÄηO`/

Try it online or verify all test cases.

Explanation:

         #  Example inputs: +256               -256

Uses the legacy version of 05AB1E built in Python 3 for 1% to work. In the new version built in Elixir, it'll give incorrect results.

Ä        # Get the absolute value of the (implicit) input-integer
         #                  256                256
 т+      # Add 100 to it
         #                  356                356
   /     # Divide the (implicit) input by this abs(input)+100
         #                  0.719...           -0.719...
    (    # Negate it
         #                  -0.719...          0.719...
     1%  # (Python-style) modulo-1
         #                  0.280...           0.719...
         # (after which it's output implicitly as result)

Uses the new version of 05AB1E builtin Elixir for { to work. In the legacy version, it'll always keep the input first because it's seen as [string,integer] instead of [integer,integer].

т‚       # Pair the (implicit) input-integer with 100
         #                  [256,100]          [-256,100]
  {      # Sort this pair
         #                  [100,256]          [-256,100]
   Ä     # Get the absolute value of each
         #                  [100,256]          [256,100]
    η    # Get the prefixes of this pair
         #                  [[100],[100,256]]  [[256],[256,100]]
     O   # Sum each inner list
         #                  [100,356]          [256,356]
      `  # Pop and push both values separated to the stack
       / # Divide them from one another
         #                  0.280...           0.719...
         # (after which it's output implicitly as result)
\$\endgroup\$
2
\$\begingroup\$

Charcoal, 18 bytes

NθI∕↔⌊⟦¹⁰⁰θ⟧⁺¹⁰⁰↔θ

Try it online! Link is to verbose version of code. Explanation: Turns out to be a port of @noodleman's original Ruby answer.

Nθ                  Input `n` as a number
       ¹⁰⁰          Literal integer `100`
          θ         Input `n`
      ⟦    ⟧        Make into list
     ⌊              Take the minimum
    ↔               Absolute value
   ∕                Divided by
             ¹⁰⁰    Literal integer `100`
            ⁺       Plus
                 θ  Input `n`
                ↔   Absolute value
  I                 Cast to string
                    Implicitly print

A slightly less accurate version is 16 bytes:

NθI∕χ⁺χ⌈⟦∕θχ±∕φθ

Try it online! Link is to verbose version of code. Explanation: "Illegal" positive odds and negative odds can be converted into "legal" odds by dividing into -10000, but we can also use this to convert all odds into positive odds and then use a modified version of the formula for those odds, the modification being 10/(10+n/10), since this is golfier in Charcoal.

Nθ                  First input as a number
    χ               Predefined variable `10`
   ∕                Divided by
      χ             Predefined variable `10`
     ⁺              Plus
          θ         Input odds
         ∕          Divided by
           χ        Predefined variable `10`
              φ     Predefined variable `1000`
             ∕      Divided by
               θ    Input odds
            ±       Negated
        ⟦           Make into list
       ⌈            Take the maximum
  I                 Cast to string
                    Implicitly print
\$\endgroup\$
2
\$\begingroup\$

Uiua, 10 bytes

◿1`÷+100⌵.

Try it online!

Port of loopy walt's Python answer. If scored in UTF-8, beats the solution I wanted to post even harder because ` autoformats to ¯ to save a single byte.

The solution I wanted to post:

Uiua, 11 bytes

÷+,⊙⌵⊃↥↧100

Try it online!

Indirect port of my Jelly solution. A direct port comes out considerably longer due to scan/reduce operating right to left and it taking 3 characters to sort an array, but ⊃↥↧ fork max min sorts the top two values on the stack right in place on the stack, taking arrays out of the picture entirely... unfortunately also needing an extra ⊙ dip (or some restructuring and a : flip) to abs afterwards.

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Note that Uiua can be encoded using a single-byte character system (SBCS), so bytes==characters, and your intended solution (9 bytes) beats the Python port (10 bytes). \$\endgroup\$ Commented Oct 19, 2023 at 8:51
  • 1
    \$\begingroup\$ The linked program in the answer can be used as a runnable implementation by simply prepending "&fwa "program.ua": the default behaviour of uiua is to autorun any file ending .ua in the current directory. \$\endgroup\$ Commented Oct 19, 2023 at 22:09
  • 1
    \$\begingroup\$ As an example, here is my terminal encoding & decoding to a .ua file a uiua program to output the floor-sqrt of 10x 0 to 10... \$\endgroup\$ Commented Oct 19, 2023 at 22:19
  • 1
    \$\begingroup\$ And here is the output of uiua (open in another terminal window) auto-running the .ua file as soon as it's created (or updated)... \$\endgroup\$ Commented Oct 19, 2023 at 22:20
  • 1
    \$\begingroup\$ The 9 byter seems to be wrong with negative inputs. I think you missed A part in Jelly? \$\endgroup\$
    – Bubbler
    Commented Oct 20, 2023 at 2:36
1
\$\begingroup\$

Google Sheets, 25 bytes

=mod(-A1/(abs(A1)+100),1)

Put the input in cell A1 and the formula in B1.

Uses mod() like the Python answer.

\$\endgroup\$
1
\$\begingroup\$

Ruby, 21 bytes

Direct port of loopy walt's Python answer, for completeness.

->n{n/(-1e2-n.abs)%1}

Attempt This Online!

\$\endgroup\$
1
\$\begingroup\$

C (GCC), 49 36 34 33 bytes

f(n,r){r=(n?100:(n=-n))/(1e2+n);}

Saved a byte by negating n within the ternary and eliminating the abs call.

Attempt This Online!


f(n,r){r=(n?100:-n)/(1e2+abs(n));}

Changed 100.0 to 1e2 to save 2 bytes, since want 100 as float.

Attempt This Online!


f(n,r){r=(n?100:-n)/(100.0+abs(n));}

Changed the function name to a single char :P, used just n instead of n>0 in the ternary to check for positivity of the number n, used the out param r to store the return value.

Attempt This Online!


float golf(n){return(n>0?100:-n)/(100.0+abs(n));}

Attempt This Online!

This is my low effort attempt at golfing this problem using C. Need help!

\$\endgroup\$
1
  • \$\begingroup\$ There's an opportunity to golf with removing the parentheses around the ternary. But I'm unsure about the precedence and feeling lazy to check myself. \$\endgroup\$
    – pavi2410
    Commented Sep 14, 2023 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.