Search code examples
phpfloating-pointintfractions

Turning Floats into Their Closest (UTF-8 Character) Fraction


I want to take any real number, and return the closest number, with the closest fraction as available in the UTF-8 character set, appropriate.

0/4 = 0.00 =   # < .125
1/4 = 0.25 = ¼ # > .125 & < .375
2/4 = 0.50 = ½ # > .375 & < .625
3/4 = 0.75 = ¾ # > .625 & < .875
4/4 = 1.00 =   # > .875

I made this function to do that task:

function displayFraction($realNumber)
{
    if (!is_float($realNumber))
    {
        return $realNumber;
    }
    list($number, $decimal) = explode('.', $realNumber);
    $decimal = '.' . $decimal;
    switch($decimal)
    {
        case $decimal < 0.125:
            return $number;
        case $decimal > 0.125 && $decimal < 0.375:
            return $number . '¼'; # 188 ¼ &#188;
        case $decimal > 0.375 && $decimal < 0.625:
            return $number . '½'; # 189 ½ &#189;
        case $decimal > 0.625 && $decimal < 0.875:
            return $number . '¾'; # 190 ¾ &#190;
        case $decimal < 0.875:
            return ++$number;
    }
}

What are the better / diffrent way to do this?

echo displayFraction(3.1) . PHP_EOL;      # Outputs: 3
echo displayFraction(3.141593) . PHP_EOL; # Outputs: 3¼
echo displayFraction(3.267432) . PHP_EOL; # Outputs: 3¼
echo displayFraction(3.38) . PHP_EOL;     # Outputs: 3½

Expand my mind!


Solution

  • You shouldn't rely on the presence of a decimal part:

    # Will generate a STRICT warning if $realNumber does not contain a full stop:
    list($number, $decimal) = explode('.', $realNumber);
    

    Try this instead:

    $integerPart = floor($realNumber);
    $decimalPart = $realPart - $integerPart;
    

    You shouldn't use a switch here, but rather if statements (it will look like it's working but give unexpected results if you input 0, for example, since you are actually comparing $decimal to the result of the expression $decimal < 0.125):

    if ($decimalPart <= 0.25) {
        # ...
    } else if ($decimalPart <= 0.5) {
        # ...
    } else if ...