This problem consists of two seperate steps
- Create a fraction from a decimal number
- Convert between betting odds and fractions
Let's start with the latter: A betting odd of 5
means, for every $1 invested, you get $5 if you win. Since you invested $1, your actual win is just $4. So the odds are 4-1 or 4/1
Analogous, betting odds of 2.5
mean, for every $1 you invest, you win $1.5, giving you 1.5-1 or 3-2 or 3/2
This leads us to the conclusion, that what we need is the fraction of ($odds-1)
Next part: Fractionizing. I didn't analyze the given algorithm, but wrote a very bad (but easily readable) one:
function dec2frac($val) {
//first pump denominator up
$tmp=strstr("$val",'.');
if ($tmp) $tmp=strlen($tmp)-1;
else $tmp=0;
$n=$val;
$d=1;
for (;$tmp>0;$tmp--) {
$n*=10;
$d*=10;
}
$n=intval(round($n));
$d=intval(round($d));
//Now shorten the fraction
//Find limit for pseudoprime search
$min=$n;
if ($d<$n) $min=$d;
$min=ceil($min/2);
if (ceil($d/2)>$min) $min=ceil($d/2);
if (ceil($n/2)>$min) $min=ceil($n/2);
$pseudoprime=2;
while ($pseudoprime<=$min) {
//Shorten by current pseudoprime as long as possible
while (true) {
$nn=$n/$pseudoprime;
if ($nn!=round($nn)) break;
$dd=$d/$pseudoprime;
if ($dd!=round($dd)) break;
$n=intval($nn);
$d=intval($dd);
}
//Move on to next pseudoprime
$pseudoprime+=($pseudoprime==2)?1:2;
if ($pseudoprime>3)
if (($pseudoprime/3)==floor($pseudoprime/3)) $pseudoprime+=2;
}
return "$n/$d";
}
This was tested to work with the values 0.25, 2.5, 3.1, 3.14, 3.141, 3.1415, 3.14159 and 3.141592.
The very unoptimized nature of the algorithm is a less important limit, as betting odds tend to have not very many decimal digits.
Together with
function odds2fract($odds) {
return dec2frac($odds-1);
}
derived from the other step, we get successfull conversion of
5 --> 4/1
2.5 --> 3/2
2.1 --> 11/10
2.2 --> 6/5
Edit
The original version had a bug in the search limit calculation, which led to some fractions (e.g. completeley shortenable) failed to be shortened. The updated version fixes this.
Edit 2
Again a fixed bug: Failing to round()
the values obtained in the first step before intval()
ing them gave wrong results on fractions, that have a very bad fidelity in floatingpoint. Fixed by applying the missing round()