Тайм-аут конверсии десятичных коэффициентов

Я пытаюсь конвертировать из десятичных в дробные спортивные шансы. Я нашел с помощью поиска функцию PHP, которая работает хорошо, но некоторые десятичные дроби вызывают проблемы, такие как 2.1, который максимизирует сервер:

    function dec2frac($dec) { 

        $decBase = --$dec; 

        $div = 1; 

        do { 

            $div++; 

            $dec = $decBase * $div; 

        } while (intval($dec) != $dec); 

        if ($dec % $div == 0) { 
            $dec = $dec / $div; 
            $div = $div / $div; 
        } 

        return $dec.'/'.$div; 

    } 

$decimal = 2.3;

echo $decimal.' --> '.dec2frac($decimal);

Десятичные шансы 6 должны давать 5/1. Это рассчитывается как 6-1=5 = 5/1

Я обнаружил, что десятичный ввод 2,2 и 2,3 отключает функцию, но другие значения, кажется, в порядке. Что вызывает эту аномалию, есть ли способ обойти это?

Благодарю.

2 ответа

Решение

Эта проблема состоит из двух отдельных шагов

  • Создать дробь из десятичного числа
  • Конвертировать между коэффициентами ставок и долей

Давайте начнем с последнего: ставки нечетные 5 означает, что за каждый вложенный 1 доллар вы получаете 5 долларов, если выиграете. Поскольку вы вложили 1 доллар, ваш фактический выигрыш составляет всего 4 доллара. Таким образом, шансы 4-1 или 4/1

Аналогичные, ставки на 2.5 значит, за каждый вложенный 1 доллар вы выигрываете 1,5 доллара, что дает вам 1,5-1 или 3-2 или 3/2

Это приводит нас к выводу, что нам нужна доля ($odds-1)

Следующая часть: Фракционирование. Я не анализировал данный алгоритм, но написал очень плохой (но легко читаемый):

function dec2frac($val) {
     //first pump denominator up
     $tmp=strstr("$val",'.');
     if ($tmp) $tmp=strlen($tmp)-1;
     else $tmp=0;
     $n=$val;
     $d=1;
     for (;$tmp>0;$tmp--) {
       $n*=10;
       $d*=10;
     }
     $n=intval(round($n));
     $d=intval(round($d));

     //Now shorten the fraction

     //Find limit for pseudoprime search
     $min=$n; 
     if ($d<$n) $min=$d;
     $min=ceil($min/2);
     if (ceil($d/2)>$min) $min=ceil($d/2);
     if (ceil($n/2)>$min) $min=ceil($n/2);

     $pseudoprime=2;
     while ($pseudoprime<=$min) {
          //Shorten by current pseudoprime as long as possible
          while (true) {
               $nn=$n/$pseudoprime;
               if ($nn!=round($nn)) break;
               $dd=$d/$pseudoprime;
               if ($dd!=round($dd)) break;
               $n=intval($nn);
               $d=intval($dd);
          }
          //Move on to next pseudoprime
          $pseudoprime+=($pseudoprime==2)?1:2;
          if ($pseudoprime>3) 
            if (($pseudoprime/3)==floor($pseudoprime/3)) $pseudoprime+=2;
     }
     return "$n/$d";
}

Это было проверено на работу со значениями 0,25, 2,5, 3,1, 3,14, 3,141, 3,1415, 3,14159 и 3,141592.

Очень неоптимизированная природа алгоритма является менее важным ограничением, так как шансы на ставку, как правило, имеют не очень много десятичных цифр.

Вместе с

function odds2fract($odds) {
    return dec2frac($odds-1);
}

полученный из другого шага, мы получаем успешное преобразование

5 --> 4/1
2.5 --> 3/2
2.1 --> 11/10
2.2 --> 6/5

редактировать

В исходной версии была ошибка в расчете предела поиска, что приводило к тому, что некоторые дроби (например, сокращаемые полные данные) не могли быть сокращены. Обновленная версия исправляет это.

Редактировать 2

Опять исправлена ​​ошибка: round() значения, полученные на первом этапе перед intval()Их использование дало неверные результаты для дробей, которые имеют очень плохую точность в плавающей точке. Исправлено путем применения отсутствующего round()

Первое, что сразу же срабатывает, это то, что вы использовали там ".1". Для меня это говорит о том, что мы имеем дело с проблемами с плавающей запятой... проверьте ваш код... да, для меня это похоже на проблемы с плавающей запятой. Проблема здесь в том, что ваши числа хранятся в двоичном виде, и для двоичного кода нет удобного способа использовать много десятичных значений. Когда вы начинаете использовать простую математику, вы не получаете точных результатов, вы получаете краткие оценки.

Числа с плавающей точкой в ​​PHP

Эта ссылка должна дать вам подробное описание того, что происходит не так, ссылки на дополнительные страницы, которые дадут вам еще больше информации, и ссылки на библиотеки, которые существуют, чтобы исправить это.

Другие вопросы по тегам