小数赔率转换超时

时间:2013-05-28 12:46:05

标签: php algorithm decimal fractions

我试图将小数转换为分数运动赔率。我通过搜索找到了一个运行良好的PHP函数,但某些小数会导致问题,例如2.1最大化服务器:

    function dec2frac($dec) { 

        $decBase = --$dec; 

        $div = 1; 

        do { 

            $div++; 

            $dec = $decBase * $div; 

        } while (intval($dec) != $dec); 

        if ($dec % $div == 0) { 
            $dec = $dec / $div; 
            $div = $div / $div; 
        } 

        return $dec.'/'.$div; 

    } 

$decimal = 2.3;

echo $decimal.' --> '.dec2frac($decimal);

小数几率为6应该给出5/1。这被计算为6-1 = 5 = 5/1

我发现2.2和2.3的十进制输入使函数跳起来但其他值似乎没问题。造成这种异常现象的原因是什么呢?

感谢。

2 个答案:

答案 0 :(得分:4)

此问题包含两个单独的步骤

  • 从十进制数字
  • 创建一个分数
  • 在赔率和分数之间转换

让我们从后者开始:5的投注奇数意味着,如果您赢得每1美元投资,您将获得5美元。由于您投入了1美元,您的实际赢额仅为4美元。所以赔率为4-1或4/1

类比,投注赔率为2.5意味着,您投资的每1美元,您赢得1.5美元,给您1.5-1或3-2或3/2

这导致我们得出结论,我们需要的是($odds-1)

的分数

下一部分:分数。我没有分析给定的算法,但写了一个非常坏(但很容易阅读)的算法:

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";
}

测试使用的值为0.25,2.5,3.1,3.14,3.141,3.1415,3.14159和3.141592。

算法的非优化性质是一个不那么重要的限制,因为投注赔率往往没有很多十进制数字。

一起
function odds2fract($odds) {
    return dec2frac($odds-1);
}
从另一步得到

,我们成功转换

5 --> 4/1
2.5 --> 3/2
2.1 --> 11/10
2.2 --> 6/5

修改

原始版本在搜索限制计算中存在错误,导致某些分数(例如,completeley缩短)无法缩短。更新版本解决了这个问题。

修改2

同样是一个固定的错误:round()intval()之前的第一步中获得的值未能round()在分数上给出错误的结果,这在浮点数上具有非常差的保真度。通过应用缺少的{{1}}

进行修复

答案 1 :(得分:0)

立即触发的第一件事就是你在那里使用'.1'。对我来说,这表明我们正在处理浮点问题......检查你的代码......是的,看起来像浮点问题。这里的问题是你的数字是以二进制形式存储的,并且二进制文件没有方便的方法来使用大量的十进制值。当你开始使用简单的数学时,你得不到精确的结果,你得到快捷方式估计。

Floating Point numbers in PHP

该链接应该为您提供有关出错的详细信息,指向更多页面的链接,这些页面将为您提供更多信息,以及指向现有库以修复它的链接。