PHP convert decimal into fraction and back?

前端 未结 14 795
面向向阳花
面向向阳花 2020-12-05 07:43

I want the user to be able to type in a fraction like:

 1/2
 2 1/4
 3

And convert it into its corresponding decimal, to be saved in MySQL,

相关标签:
14条回答
  • 2020-12-05 08:08

    The fraction to decimal is quite straightforward and there are lots of solutions. I'd go with trimming the string, replacing spaces with '+', and anything other than space,/,. or digits with '' then running it through 'eval'.

    The decimal to fraction is virtually impossible to do correctly - not least because your decimal fraction would probably have to be converted to binary first - at which point you loose a lot of precision. As an academic exercise.....If you can live with the difference between 20976/41953 and 1/2 then you could try a fuzzy match for a predefined number of fractions:

    (there's probably a neater way of implementing the same algorithm - but I'll leave that as an exercise for the reader).

    define('DECIMAL_DIGITS',5);
    
    function decimal_2_frac($inp_decimal)
    {
      static $fracs;
      if (!is_array($fracs)) {
        init_fracs($fracs);
      }
      $int_part=(integer)$inp_decimal;
      $inp_decimal=$inp_decimal-$int_part;
      $candidate='';
      $distance=10;
      foreach ($fracs as $decimal=>$frac) {
         if (abs($decimal-$inp_decimal)<$distance) {
           $candidate=$frac;
           $distance=abs($decimal-$inp_decimal);
         }
      if (abs($decimal-$inp_decimal)>$distance) {
         break;
      }
     }
     return $int_part . ' ' . $candidate;
    }
    
    function init_fracs(&$fracs)
    {
       $fracs=array(); 
       for ($x=2;$x<(5*DECIMAL_DIGITS);$x++) {
           // there's probably a beter way to calculate the loop limit
          for ($y=1; $y<$x; $y++) {
             $decimal=round($y/$x,DECIMAL_DIGITS);
             $frac="$x/$y";
             if (!array_key_exists($decimal,$fracs)) {
             $fracs[$decimal]=$frac;
       }
      }    
     }
    }
    

    But personally, I'd just store the original representation in a seperate field in the database.

    0 讨论(0)
  • 2020-12-05 08:09
    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;
    }
    
    0 讨论(0)
  • 2020-12-05 08:11

    I think I'd store the string representation too, as, once you run the math, you're not getting it back!

    And, here's a quick-n-dirty compute function, no guarantees:

    $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;
    

    Oh, for completeness, add a check to make sure $fraction['denominator'] != 0.

    0 讨论(0)
  • 2020-12-05 08:12

    To can use PEAR's Math_Fraction class for some of your needs

    <?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();
    
    ?>
    
    0 讨论(0)
  • 2020-12-05 08:21

    Little improvement on above, but keepin it simple.

    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;
    }
    
    0 讨论(0)
  • 2020-12-05 08:24

    Just adding a bit more logic to Derek's accepted answer - check for "division by zero" and whole number input check.

    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;
    }
    
    0 讨论(0)
提交回复
热议问题