0

我正在尝试将运动赔率从小数转换为分数。我通过搜索找到了一个运行良好的 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 的十进制输入会使函数跳闸,但其他值似乎没问题。是什么导致了这个异常,有办法解决吗?

谢谢。

4

2 回答 2

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

编辑

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

编辑 2

又是一个固定的错误:未能round()在第一步中获得的值在intval()ing 之前给出了错误的分数结果,这些结果在浮点方面的保真度非常差。通过应用缺失来修复round()

于 2013-05-28T13:41:57.617 回答
0

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

PHP中的浮点数

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

于 2013-05-28T13:00:16.407 回答