2014-10-08 2 views
0

Вот проблема, когда он сталкивается с такими фракциями, как: 300/10 вместо того, чтобы давать результат «30» , следующий код дает мне : 1/0Исправление для преобразования фракции короткий PHP-фрагмент, выпуск с вычислением, преобразование фракции в более читаемый формат

$tokens = explode('/', $value); 
while ($tokens[0] % 10 == 0) { 
    $tokens[0] = $tokens[0]/10; 
    $tokens[1] = $tokens[1]/10; 
} 
if ($tokens[1] == 1) { 
    return $tokens[0].' s'; 
} else { 
    return '1/'.floor(1/($tokens[0]/$tokens[1])).' s'; 
    // return $tokens[0].'/'.$tokens[1].' s'; 
} 

благодарит

+1

В то же время, когда итерация '$ tokens [0] = 30 (300/10)', '$ tokens [1] = 1 (10/10)', вторая - итерация '$ tokens [0 ] = 3 (30/10) ',' $ tokens [1] = 0,1 (1/10) ',' else' работает. –

+0

, потому что вы уменьшили $ tokens [1] до 0,1 – Hammerstein

+0

U_mulder и Hammer благодарим за комментарии, но, пожалуйста, укажите, как вы предлагаете модифицировать мой код, чтобы лучше всего покрыть такие случаи и сделать его ответом на вопрос, чтобы я мог щелкнуть ', чтобы принять ваш ответ как лучшее решение. спасибо – htfree

ответ

0

Вы должны изменить линию while($tokens[0] % 10 === 0 && $tokens[1] % 10 === 0) { к while($tokens[0] % 10 === 0 && $tokens[1] % 10 === 0) {.

И линия return '1/'.floor(1/($tokens[0]/$tokens[1])).' s'; надежна.

Если вы хотите, чтобы уменьшить фракции, попробуйте эту функцию:

function reduceFraction($fraction) { 
    sscanf($fraction, '%d/%d %s', $numerator, $denominator, $junk); 

    // TODO: validation 

    if($denominator === null) { 
     return (string)$numerator; 
    } 

    if($numerator === $denominator) { 
     return 1; 
    } 

    $max = max(array($numerator, $denominator)); 
    for($i = 1; $i < $max; ++$i) { 
     if($denominator % $i === 0 && $numerator % $i === 0) { 
      $common = $i; 
     } 
    } 

    if($denominator === $common) { 
     return (string)($numerator/$common); 
    } 

    return ($numerator/$common) . '/' . ($denominator/$common); 
} 

Вы могли бы использовать его как это: reduceFraction ('300/10'). 's';

Также возможно обобщить функцию для цепных фракций (например, «300/100/10»). Я могу отправить его, если хотите.

+0

Спасибо, я попробовал вашу модификацию и, похоже, сделал то же самое, что и мое исправление смены% 10 на «% 100», так что вы можете сказать мне, почему «while» ($ tokens [0]% 10 == 0 && $ tokens [ 1]% 10 == 0) «было бы лучше использовать, чем просто» while ($ tokens [0]% 100 == 0) », поскольку оба метода работают нормально. Затем я нажимаю, чтобы принять ответ, спасибо – htfree

+0

Я добавил еще один ответ, объясняющий, почему «while» ($ tokens [0]% 10 == 0 && $ tokens [1]% 10 == 0) «лучше, чем» while ($ tokens [0]% 100 == 0) ". Они оба возвращают одну и ту же строку, когда вы используете «300/10» в качестве аргумента («30 с»), но они возвращают разные строки, когда вы используете «3000/10» в качестве аргумента («1/0 с» и «30 s "). Позднее (мое предложение) является тем, которое возвращает правильное значение, но я предлагаю вам использовать реализацию «сокращение», поскольку он работает для любой доли n/m. –

0

скажите мне, почему "в то время как ($ токенов [0]% 10 == 0 & & $ лексемы [1]% 10 == 0)" будет лучше, чем просто «в то время как ($ лексемы [0]% 100 == 0)», так как оба метода, кажется, работает нормально

Если вы пытаетесь использовать строку„3000/10“в качестве аргумента для каждой реализации, одна с while ($tokens[0] % 10 == 0 && $tokens[1] % 10 ==0) вернется 300 s , а другой с while ($tokens[0] % 100 == 0) вернет 1/0 s.

Если вы используете метод while ($tokens[0] % 100 == 0) итерации цикла являются:

  1. $tokens[0] = 3000/10 = 300; $tokens[1] = 10/10 = 10;
  2. $tokens[0] = 30/10 = 30; $tokens[1] = 10/1 = .1; Остановился, потому что 30% 100 = 0. Поскольку $ лексема [1] не 1, то не возвращается «30 с». 1/30 меньше нуля (0.0333 ...), таким образом, пол (1/30) = 0. Вот почему он возвращает «1/0 с».

Если вы используете метод while ($tokens[0] % 10 == 0 && $tokens[1] % 10 == 0) итерации цикла являются:

  1. $tokens[0] = 3000/10 = 300; $tokens[1] = 10/10 = 1; Остановился потому, что 1% 10 = 0. Поскольку $ лексема [1] не 1, она возвращает "! 30 с ".

Это лучше, потому что оно будет работать с большим количеством входов.

Но я рекомендую вам использовать функцию «уменьшить», которую я реализовал.

Он использует максимальную общую технику знаменателя для уменьшения функций.

  • echo reduceFraction('3000/10'); Выходы "300".
  • echo reduceFraction('300/10'); выходы "30".
  • echo reduceFraction('30/10'); выходы "3".
  • echo reduceFraction('3/10'); выходы "3/10".
  • echo reduceFraction('3/3'); выходы "1".
  • echo reduceFraction('222/444'); выходы "1/2".
  • echo reduceFraction('444/222'); выходы "2".
Смежные вопросы