PHP是否将小数转换为小数并返回?

PHP是否将小数转换为小数并返回?,php,decimal,fractions,Php,Decimal,Fractions,我希望用户能够键入一个分数,如: 1/2 2 1/4 3 并将其转换为相应的十进制数,保存在MySQL中,这样我就可以按它排序并与它进行其他比较 但是我需要能够在向用户显示时将小数转换回小数 所以基本上我需要一个将分数字符串转换为十进制的函数: fraction_to_decimal("2 1/4");// return 2.25 以及一个可以将十进制数转换为字符串的函数: decimal_to_fraction(.5); // return "1/2" 我怎样才能做到这一点呢?我想

我希望用户能够键入一个分数,如:

 1/2
 2 1/4
 3
并将其转换为相应的十进制数,保存在MySQL中,这样我就可以按它排序并与它进行其他比较

但是我需要能够在向用户显示时将小数转换回小数

所以基本上我需要一个将分数字符串转换为十进制的函数:

fraction_to_decimal("2 1/4");// return 2.25
以及一个可以将十进制数转换为字符串的函数:

decimal_to_fraction(.5); // return "1/2"

我怎样才能做到这一点呢?

我想我也应该存储字符串表示,因为一旦你运行了数学运算,你就不会得到它了

这里有一个quick-n-dirty计算函数,不能保证:

$input = '1 1/2';
$fraction = array('whole' => 0);
preg_match('/^((?P<whole>\d+)(?=\s))?(\s*)?(?P<numerator>\d+)\/(?P<denominator>\d+)$/', $input, $fraction);
$result = $fraction['whole'] + $fraction['numerator']/$fraction['denominator'];
print_r($result);die;
$input='1 1/2';
$fraction=数组('整'=>0);
预匹配('/^((?P\d+(=\s))?(\s*)?(?P\d+)\/(?P\d+)$/',$input,$fraction);
$result=$fraction[‘整’]+$fraction[‘分子’]/$fraction[‘分母’];
打印(结果);死亡

哦,为了完整性,请添加一个检查以确保
$fraction['deminator']!=0

可以使用PEAR的数学分数课程满足您的部分需求

<?php

include "Math/Fraction.php";

$fr = new Math_Fraction(1,2);


// print as a string
// output: 1/2
echo $fr->toString();

// print as float
// output: 0.5
echo $fr->toFloat();

?>

一种方法是检索十进制值并将其乘以2、3、4等,直到得到一个整数

不过,我还是坚持德里克给出的答案。猜猜当用户插入n/(n+1)且n高时会发生什么。这种算法必须扫描n+1以内的所有数字。
更不用说你可能会遇到近似问题。

你将不得不面对一个严重的问题,因为浮点值不够精确

当您必须处理
1.3333
时,PHP将对此值进行估计。。。因此,您将永远无法将其转换为
1 1/3

这似乎很容易克服,但如果您想让您的程序将
1/7901
~126566257457676243513479064169E-4
)与
1/7907
~
12647021626406981155937776653598E-4
)正是。。。这将是一个真正的地狱

如果你想学习数学,你应该依靠外部的图书馆。。。或者尝试让PHP与Matlab通信


如果你想知道更多,我建议你深入研究浮点问题。。。从.

开始,如果只使用有限数量的分母,Jir方法的一种变体实际上可以起作用:将所有分母乘以最小公分母(并将结果四舍五入,以丢弃由于近似而剩下的任何小数)

也就是说:如果你只需要处理一半、三倍和四分之一,就把所有的数乘以12

而且,如果你知道公分母,这将大大降低搜索速度,因为你可以准确地知道要搜索哪些数字,而不是搜索所有可能的n+1


如果你必须处理很多不寻常的分数,比如1/7、1/13等。那么,坚持Derek的解决方案并存储原始值。

小数点的分数非常简单,有很多解决方案。我会修剪字符串,用“+”替换空格,以及除空格、/,”以外的任何内容,。或带“”的数字,然后通过“eval”运行它

小数到小数的转换实际上是不可能正确完成的——尤其是因为您的小数可能必须首先转换为二进制——在这一点上,您失去了很多精度。作为一项学术练习……如果你能接受20976/41953和1/2之间的差异,那么你可以尝试对预定义分数进行模糊匹配:

(可能有一种更简洁的方法来实现相同的算法——但我将把它留给读者作为练习)

define('DECIMAL_DIGITS',5);
函数十进制2分位数($inp\U十进制)
{
静态压裂;
如果(!is_数组($fracs)){
初始压裂(压裂);
}
$int_part=(整数)$inp_decimal;
$inp_decimal=$inp_decimal-$int_部分;
$candidate='';
$distance=10;
foreach($fracs as$decimal=>$frac){
if(绝对值($decimal-$inp_decimal)$距离){
打破
}
}
返回$int_part.'.$candidate;
}
函数初始分形(&$fracs)
{
$fracs=array();

对于($x=2;$x有时您需要找到一种方法来进行此操作,舍入是可以接受的。因此,如果您决定舍入的范围适合您,您可以构建这样的函数。要将小数转换为最匹配的分数,您可以通过添加更多待测试的分母来扩展精度

function decToFraction($float) {
    // 1/2, 1/4, 1/8, 1/16, 1/3 ,2/3, 3/4, 3/8, 5/8, 7/8, 3/16, 5/16, 7/16,
    // 9/16, 11/16, 13/16, 15/16
    $whole = floor ( $float );
    $decimal = $float - $whole;
    $leastCommonDenom = 48; // 16 * 3;
    $denominators = array (2, 3, 4, 8, 16, 24, 48 );
    $roundedDecimal = round ( $decimal * $leastCommonDenom ) / $leastCommonDenom;
    if ($roundedDecimal == 0)
        return $whole;
    if ($roundedDecimal == 1)
        return $whole + 1;
    foreach ( $denominators as $d ) {
        if ($roundedDecimal * $d == floor ( $roundedDecimal * $d )) {
            $denom = $d;
            break;
        }
    }
    return ($whole == 0 ? '' : $whole) . " " . ($roundedDecimal * $denom) . "/" . $denom;
}
然后
$f==$n/$d

例如:

print_r(dec2frac(3.1415926));
产出:

Array
(
    [0] => 3537118815677477  // $n
    [1] => 1125899906842624  // $d
)

伙计们,这能帮上忙吗

[]s



上面的改进不大,但保持简单。


这里有一个解决方案,首先确定一个有效的分数(虽然不一定是最简单的分数)。因此0.05->5/100。然后确定分子和分母的最大公约数,将其减少到最简单的分数,1/20

function decimal_to_fraction($fraction) {
  $base = floor($fraction);
  $fraction -= $base;
  if( $fraction == 0 ) return $base;
  list($ignore, $numerator) = preg_split('/\./', $fraction, 2);
  $denominator = pow(10, strlen($numerator));
  $gcd = gcd($numerator, $denominator);
  $fraction = ($numerator / $gcd) . '/' . ($denominator / $gcd);
  if( $base > 0 ) {
    return $base . ' ' . $fraction;
  } else {
    return $fraction;
  }
}

# Borrowed from: http://www.php.net/manual/en/function.gmp-gcd.php#69189
function gcd($a,$b) {
  return ($a % $b) ? gcd($b,$a % $b) : $b;
}
这包括gcd的纯PHP实现,尽管如果您确定安装了gmp模块,您可以


正如许多其他人指出的那样,你需要使用有理数。因此,如果你将1/7转换为十进制,然后尝试将其转换回十进制,你将失去运气,因为丢失的精度将阻止它返回到1/7。就我而言,这是可以接受的,因为我处理的所有数字(标准测量)反正都是有理数。

我在博客上发表了一篇文章,介绍了一些解决方案,我最近采用的方法是:

函数dec2fracso($dec){
//负数标志。
$num=$dec;

如果($num),只需在Derek接受的答案中添加多一点逻辑——检查“零除”和整数输入检查

function fractionToDec($input) {
    if (strpos($input, '/') === FALSE) {
        $result = $input;
    } else {
        $fraction = array('whole' => 0);
        preg_match('/^((?P<whole>\d+)(?=\s))?(\s*)?(?P<numerator>\d+)\/(?P<denominator>\d+)$/', $input, $fraction);
        $result = $fraction['whole'];

        if ($fraction['denominator'] > 0)
            $result += $fraction['numerator'] / $fraction['denominator'];
    }

    return $result;
}
函数fractionToDec($input){
if(strpos($input,“/”)==FALSE){
$result=$input;
}否则{
$fraction=数组('整'=>0);
预匹配('/^((?P\d+(=\s))?(\s*)?(?P\d+)\/(?P\d+)$/',$input,$fraction);
$result=$fraction['full'];
如果($fractio
function toFraction($number) {
    if (!is_int($number)) {
        $number = floatval($number);
        $denominator = round(1 / $number);

        return "1/{$denominator}";
    }
    else {
        return $number;
    }
}
function dec2frac($f) {
  $base = floor($f);
  if ($base) {
    $out = $base . ' ';
    $f = $f - $base;
  }
  if ($f != 0) {
    $d = 1;
    while (fmod($f, 1) != 0.0) {
      $f *= 2;
      $d *= 2;
    }
    $n = sprintf('%.0f', $f);
    $d = sprintf('%.0f', $d);
    $out .= $n . '/' . $d;
  }
  return $out;
}
function decimal_to_fraction($fraction) {
  $base = floor($fraction);
  $fraction -= $base;
  if( $fraction == 0 ) return $base;
  list($ignore, $numerator) = preg_split('/\./', $fraction, 2);
  $denominator = pow(10, strlen($numerator));
  $gcd = gcd($numerator, $denominator);
  $fraction = ($numerator / $gcd) . '/' . ($denominator / $gcd);
  if( $base > 0 ) {
    return $base . ' ' . $fraction;
  } else {
    return $fraction;
  }
}

# Borrowed from: http://www.php.net/manual/en/function.gmp-gcd.php#69189
function gcd($a,$b) {
  return ($a % $b) ? gcd($b,$a % $b) : $b;
}
    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;
}
function fractionToDec($input) {
    if (strpos($input, '/') === FALSE) {
        $result = $input;
    } else {
        $fraction = array('whole' => 0);
        preg_match('/^((?P<whole>\d+)(?=\s))?(\s*)?(?P<numerator>\d+)\/(?P<denominator>\d+)$/', $input, $fraction);
        $result = $fraction['whole'];

        if ($fraction['denominator'] > 0)
            $result += $fraction['numerator'] / $fraction['denominator'];
    }

    return $result;
}
function frac2dec($fraction) {
    list($whole, $fractional) = explode(' ', $fraction);

    $type = empty($fractional) ? 'improper' : 'mixed';

    list($numerator, $denominator) = explode('/', $type == 'improper' ? $whole : $fractional);

    $decimal = $numerator / ( 0 == $denominator ? 1 : $denominator );

    return $type == 'improper' ? $decimal : $whole + $decimal;
}
$fraction = Fraction::fromFloat(1.5);
echo "Fraction is: " . $fraction->getNumerator() . '/' . $fraction->getDenominator();
echo "Float is: " . $fraction->toFloat();