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.
C.