Php 将浮点小数转换为小数

Php 将浮点小数转换为小数,php,math,floating-point,type-conversion,rational-numbers,Php,Math,Floating Point,Type Conversion,Rational Numbers,我试图将用户输入的十进制结果转换成分数。例如:。;66.6667转换为66 2/3。有什么建议吗? 在这种情况下,Thanx预先票价分数非常有用 它们可以用来将任何小数转换成分母可能最小的分数 抱歉-我没有PHP原型,因此这里有一个Python原型: def farey(v, lim): """No error checking on args. lim = maximum denominator. Results are (numerator, denominator

我试图将用户输入的十进制结果转换成分数。例如:。;66.6667转换为66 2/3。有什么建议吗?
在这种情况下,Thanx预先

票价分数非常有用

它们可以用来将任何小数转换成分母可能最小的分数

抱歉-我没有PHP原型,因此这里有一个Python原型:

def farey(v, lim):
    """No error checking on args.  lim = maximum denominator.
        Results are (numerator, denominator); (1, 0) is 'infinity'."""
    if v < 0:
        n, d = farey(-v, lim)
        return (-n, d)
    z = lim - lim   # Get a "zero of the right type" for the denominator
    lower, upper = (z, z+1), (z+1, z)
    while True:
        mediant = (lower[0] + upper[0]), (lower[1] + upper[1])
        if v * mediant[1] > mediant[0]:
            if lim < mediant[1]:
                return upper
            lower = mediant
        elif v * mediant[1] == mediant[0]:
            if lim >= mediant[1]:
                return mediant
            if lower[1] < upper[1]:
                return lower
            return upper
        else:
            if lim < mediant[1]:
                return lower
            upper = mediant
def票价(v,lim):
“”“检查args时没有错误。lim=最大分母。
结果是(分子,分母);(1,0)是‘无限’
如果v<0:
n、 d=票价(-v,直线度)
返回(-n,d)
z=lim-lim#得到分母的“正确类型的零”
下,上=(z,z+1),(z+1,z)
尽管如此:
中音=(下[0]+上[0]),(下[1]+上[1])
如果v*mediant[1]>mediant[0]:
如果lim<中间点[1]:
返回上
下中音
elif v*中间点[1]==中间点[0]:
如果lim>=中间点[1]:
返回中间点
如果较低[1]<较高[1]:
返回较低
返回上
其他:
如果lim<中间点[1]:
返回较低
上中音
可用于找到严格意义上“最佳”实数的有理近似值。下面是一个PHP函数,该函数查找给定(正)浮点数的有理近似值,相对误差小于
$tolerance

<?php
function float2rat($n, $tolerance = 1.e-6) {
    $h1=1; $h2=0;
    $k1=0; $k2=1;
    $b = 1/$n;
    do {
        $b = 1/$b;
        $a = floor($b);
        $aux = $h1; $h1 = $a*$h1+$h2; $h2 = $aux;
        $aux = $k1; $k1 = $a*$k1+$k2; $k2 = $aux;
        $b = $b-$a;
    } while (abs($n-$h1/$k1) > $n*$tolerance);

    return "$h1/$k1";
}

printf("%s\n", float2rat(66.66667)); # 200/3
printf("%s\n", float2rat(sqrt(2)));  # 1393/985
printf("%s\n", float2rat(0.43212));  # 748/1731

将应答中的Python代码从@APerson241转换为PHP

<?php
function farey($v, $lim) {
    // No error checking on args.  lim = maximum denominator.
    // Results are array(numerator, denominator); array(1, 0) is 'infinity'.
    if($v < 0) {
        list($n, $d) = farey(-$v, $lim);
        return array(-$n, $d);
    }
    $z = $lim - $lim;   // Get a "zero of the right type" for the denominator
    list($lower, $upper) = array(array($z, $z+1), array($z+1, $z));
    while(true) {
        $mediant = array(($lower[0] + $upper[0]), ($lower[1] + $upper[1]));
        if($v * $mediant[1] > $mediant[0]) {
            if($lim < $mediant[1]) 
                return $upper;
            $lower = $mediant;
        }
        else if($v * $mediant[1] == $mediant[0]) {
            if($lim >= $mediant[1])
                return $mediant;
            if($lower[1] < $upper[1])
                return $lower;
            return $upper;
        }
        else {
            if($lim < $mediant[1])
                return $lower;
            $upper = $mediant;
        }
    }
}

// Example use:
$f = farey(66.66667, 10);
echo $f[0], '/', $f[1], "\n"; # 200/3
$f = farey(sqrt(2), 1000);
echo $f[0], '/', $f[1], "\n";  # 1393/985
$f = farey(0.43212, 2000);
echo $f[0], '/', $f[1], "\n";  # 748/1731

以下是我解决这个问题的方法。适用于有理数

function dec2fracso($dec){
    //Negative number flag.
    $num=$dec;
    if($num<0){
        $neg=true;
    }else{
        $neg=false;
    }

    //Extracts 2 strings from input number
    $decarr=explode('.',(string)$dec);

    //Checks for divided by zero input.
    if($decarr[1]==0){
        $decarr[1]=1;
        $fraccion[0]=$decarr[0];
        $fraccion[1]=$decarr[1];
        return $fraccion;
    }

    //Calculates the divisor before simplification.
    $long=strlen($decarr[1]);
    $div="1";
    for($x=0;$x<$long;$x++){
        $div.="0";
    }

    //Gets the greatest common divisor.
    $x=(int)$decarr[1];
    $y=(int)$div;
    $gcd=gmp_strval(gmp_gcd($x,$y));

    //Calculates the result and fills the array with the correct sign.
    if($neg){
        $fraccion[0]=((abs($decarr[0])*($y/$gcd))+($x/$gcd))*(-1);
    }else{
        $fraccion[0]=(abs($decarr[0])*($y/$gcd))+($x/$gcd);
    }
    $fraccion[1]=($y/$gcd);
    return $fraccion;
}
函数dec2fracso($dec){
//负数标志。
$num=$dec;

如果($num基于@Joni的答案,这里是我用来提取整数的方法

function convert_decimal_to_fraction($decimal){

    $big_fraction = float2rat($decimal);
    $num_array = explode('/', $big_fraction);
    $numerator = $num_array[0];
    $denominator = $num_array[1];
    $whole_number = floor( $numerator / $denominator );
    $numerator = $numerator % $denominator;

    if($numerator == 0){
        return $whole_number;
    }else if ($whole_number == 0){
        return $numerator . '/' . $denominator;
    }else{
        return $whole_number . ' ' . $numerator . '/' . $denominator;
    }
}

function float2rat($n, $tolerance = 1.e-6) {
    $h1=1; $h2=0;
    $k1=0; $k2=1;
    $b = 1/$n;
    do {
        $b = 1/$b;
        $a = floor($b);
        $aux = $h1; $h1 = $a*$h1+$h2; $h2 = $aux;
        $aux = $k1; $k1 = $a*$k1+$k2; $k2 = $aux;
        $b = $b-$a;
    } while (abs($n-$h1/$k1) > $n*$tolerance);

    return "$h1/$k1";
}

有时只需要处理浮点数的小数,所以我创建了一个代码,使用@Joni创建的函数来呈现一种在烹饪食谱中非常常见的格式,至少在巴西是如此

因此,使用我创建的函数可以表示值1 1/2,而不是使用1.5的结果3/2,如果需要,还可以添加字符串来连接值,创建类似“1和1/2”的内容


根据@APerson和@Jeff Monteiro的答案,我创建了PHP版本的Farey分数,该分数将简化为具有最小分母分数的整数值:


66 2/3!=66.666667,所以你必须进行猜测。但这不是66 2/3!这是66666 7/1000000000。你如何区分两者之间的差异?什么是“合理的”四舍五入?输出为66.666667,当它应该是无止境的6秒时。那么我如何将输出更改为2/3?不能进行四舍五入,否则最终答案将不是2/3…显然你不能有“无止境”6s,没有无限的内存。这是我的一个从浮点中提取分数的方法。不确定翻译成PHP有多困难,但可能值得一看。Thanx是一个友好的手势,但我真的无法尝试将其转换成PHP…Thanx再次tho…如果有人能帮助这个python结构转换成PHP?python代码使用s元组作为一种大大缩短代码的方法。代码中的
下部
上部
可以被视为大小为2的数组,这两个数组都可以“解包”分为两个变量。大多数代码都是比较
lower
upper
中的项目,并将它们设置为彼此相等,这样就可以相对容易地转换为PHP。谢谢@APerson,我能够使用这种方法改进食谱中的措施。我在这里添加了我的答案→ 函数中有一个小错误,如果
$b==$a
将抛出一个警告,“除以0”在@adrian7,我不知道PHP的这一方面——在其他语言中,浮点除以0表现良好。如果
$b===$a
循环是在最后一次迭代中,那么将除法从循环的末尾移到开头就解决了问题。我已经更新了代码。因为它很简单,我可以自由地添加ha负数的NDL。我希望这是根据SO规则可以完成的事情:|
function float2rat($n, $tolerance = 1.e-6) {
  $h1=1; $h2=0;
  $k1=0; $k2=1;
  $b = 1/$n;
  do {
      $b = 1/$b;
      $a = floor($b);
      $aux = $h1; $h1 = $a*$h1+$h2; $h2 = $aux;
      $aux = $k1; $k1 = $a*$k1+$k2; $k2 = $aux;
      $b = $b-$a;
  } while (abs($n-$h1/$k1) > $n*$tolerance);

  return "$h1/$k1";
}

function float2fraction($float, $concat = ' '){
  
  // ensures that the number is float, 
  // even when the parameter is a string
  $float = (float)$float;

  if($float == 0 ){
    return $float;
  }
  
  // when float between -1 and 1
  if( $float > -1 && $float < 0  || $float < 1 && $float > 0 ){
    $fraction = float2rat($float);
    return $fraction;
  }
  else{

    // get the minor integer
    if( $float < 0 ){
      $integer = ceil($float);
    }
    else{
      $integer = floor($float);
    }

    // get the decimal
    $decimal = $float - $integer;

    if( $decimal != 0 ){

      $fraction = float2rat(abs($decimal));
      $fraction = $integer . $concat . $fraction;
      return $fraction;
    }
    else{
      return $float;
    }
  }
}
echo float2fraction(1.5);
will return "1 1/2"