views:

43

answers:

3

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!

+2  A: 

You implemented a statically compiled search algorithm for picking the fractions. So long as the number of unicode fractions doesn't change much (which it won't), then what you have is fine. Move on.

If you lived in a world where the unicode fractions did change often. Then you should switch your search from being hard coded to data-driven. Just have a table of fraction values and their unicode equivalent. Search the table for the closest fraction, then use the associated unicode char.

Frank Krueger
+2  A: 

One could be "clever" and take (188 + (decimal-0.125) * 4) for the case when decimal is between 0.125 and 0.875, but that would be more obfuscating than clever, IMO. That said, you probably want your last case to be > 0.875 and not < 0.875.

Ben Hocking
You also gave a great answer, I wish I could give more then just an up vote for that, as for this question there was more then one right answer, where as soul gave the most correct answer, I felt. Still, thank you for your input, you have given me ideas, and some things to think about.
Mark Tomlin
+1  A: 

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