修复了转换分数的PHP短代码段,将分数转换为更可读格式的计算问题

修复了转换分数的PHP短代码段,将分数转换为更可读格式的计算问题,php,arrays,token,explode,fractions,Php,Arrays,Token,Explode,Fractions,当它遇到像:300/10这样的分数而不是给出“30”的结果时,问题就出现了 下面的代码给了我:1/0 $tokens = explode('/', $value); while ($tokens[0] % 10 == 0) { $tokens[0] = $tokens[0] / 10; $tokens[1] = $tokens[1] / 10; } if ($tokens[1] == 1) { return $tokens[0].' s'; } else { return

当它遇到像:300/10这样的分数而不是给出“30”的结果时,问题就出现了 下面的代码给了我:1/0

$tokens = explode('/', $value);
while ($tokens[0] % 10 == 0) {
   $tokens[0] = $tokens[0] / 10;
   $tokens[1] = $tokens[1] / 10;
}
if ($tokens[1] == 1) {
   return $tokens[0].' s';
} else {
  return '1/'.floor(1/($tokens[0]/$tokens[1])).' s';
   // return $tokens[0].'/'.$tokens[1].' s';
}

谢谢

您应该将while($tokens[0]%10==0&&$tokens[1]%10==0){更改为
while($tokens[0]%10==0&$tokens[1]%10==0){

而行
返回'1/'。floor(1/($tokens[0]/$tokens[1])。's';
不可靠

如果要减少分数,请尝试此函数:

function reduceFraction($fraction) {
    sscanf($fraction, '%d/%d %s', $numerator, $denominator, $junk);

    // TODO: validation

    if( $denominator === null ) {
        return (string)$numerator;
    }

    if( $numerator === $denominator ) {
        return 1;
    }

    $max = max(array($numerator, $denominator));
    for($i = 1; $i < $max; ++$i) {
        if( $denominator % $i === 0 && $numerator % $i === 0) {
            $common = $i;
        }
    }

    if( $denominator === $common ) {
        return (string)($numerator / $common);
    }

    return ($numerator / $common) . '/' . ($denominator / $common);
}
函数简化动作($fraction){
sscanf($分数、%d/%d%s',$分子、$分母、$垃圾);
//TODO:验证
如果($分母===null){
返回(字符串)$分子;
}
如果($分子===$分母){
返回1;
}
$max=max(数组($分子,$分母));
对于($i=1;$i<$max;++$i){
如果($分母%$i==0&$分子%$i==0){
$common=$i;
}
}
如果($分母===$公共){
返回(字符串)($momerator/$common);
}
返回($分子/$公共)。“/”($分母/$公共);
}
您可以这样使用它: 还原反应('300/10').'s'

还可以对链式分数(例如:“300/100/10”)的函数进行更多的泛化。如果您愿意,我可以发送它的实现

告诉我为什么“while($tokens[0]%10==0&&$tokens[1]%10==0”) 最好不要只使用“while($tokens[0]%100==0)”因为 两种方法似乎都可以

如果尝试使用字符串“3000/10”作为每个实现的参数,则带有
while($tokens[0]%10==0&&$tokens[1]%10==0)
的一个将返回
300秒
,而带有
while($tokens[0]%100==0)
的另一个将返回
1/0秒

如果使用
while($tokens[0]%100==0)
方法,则循环迭代为:

  • $tokens[0]=3000/10=300;
    $tokens[1]=10/10=10;
  • $tokens[0]=30/10=30;
    $tokens[1]=10/1=.1;
    已停止,因为30%100!=0。 由于$token[1]不是1,因此它不会返回“30秒”。 1/30小于零(0.0333…),因此地板(1/30)=0。这就是它返回“1/0 s”的原因
  • 如果使用
    while($tokens[0]%10==0&&$tokens[1]%10==0)
    方法,循环迭代为:

  • $tokens[0]=3000/10=300;
    $tokens[1]=10/10=1;
    已停止,因为1%10!=0。 由于$token[1]不是1,因此它返回“30秒”
  • 它更好,因为它可以处理更多的输入

    但我建议您使用我实现的“reduceFraction”函数

    它使用最大公分母技术来减少函数

    • echo reducerfaction('3000/10');
      输出“300”
    • echo reducerfaction('300/10');
      输出“30”
    • echo reducerfaction('30/10');
      输出“3”
    • echo reducerfaction('3/10');
      输出“3/10”
    • 回波还原动作('3/3');
      输出“1”
    • 回波还原动作('222/444');
      输出“1/2”
    • 回波还原动作('444/222');
      输出“2”

    在第一次while迭代中,
    $tokens[0]=30(300/10)
    $tokens[1]=1(10/10)
    ,在第二次while迭代中,
    $tokens[0]=3(30/10)
    $tokens[1]=0.1(1/10)
    ,否则案例有效。因为您减少了$tokens[1]0.1U_mulder and Hammer感谢您的评论,但请具体说明您将如何建议修改我的代码以最好地涵盖此类情况,并将其作为问题的答案,以便我可以“单击”以接受您的答案作为最佳解决方案。感谢换句话说,我自己的快速解决方案只是将%10更改为%100,但这可能会破坏一些细节g还有另一个case/fraction样式,不是最佳修复方法吗?我现在感觉不太好,所以思考不太好。谢谢,我尝试了你的修改,似乎做了与我将%10更改为“%100”的修复相同的事情,所以你能告诉我为什么“while($tokens[0]%10==0&$tokens[1]%10==0)”比“while”更好用吗($tokens[0]%100==0)”因为这两种方法似乎都能正常工作。然后我将单击以接受答案,thanksI添加了另一个答案,解释了为什么“while($tokens[0]%10==0&$tokens[1]%10==0)”优于“while($tokens[0]%100==0”。当您使用“300/10”作为参数(“30 s”)时,它们都返回相同的字符串,但当您使用“3000/10”作为参数(“1/0 s”和“30 s”)时,它们返回不同的字符串。后一个(我的建议)是返回正确值的字符串,但我建议您使用“reduceFraction”实现,因为它适用于任何分数n/m。