БлогNot. PHP: перевести бесконечную периодическую дробь в обыкновенную

PHP: перевести бесконечную периодическую дробь в обыкновенную

На самом деле, задачка вот такая:

Заданы натуральные величины а, b, c, где а — целая часть вещественного числа, b — дробная часть до периода, с — период. Получить число в виде обыкновенной дроби вида m/n, где m — числитель, n — знаменатель.

Суть в том, что некоторые дроби конечны, например, 1/4 = 0,25, а некоторые - нет, скажем, 1/3 = 0,3333333..., это можно записать как тройку чисел (0,false,3) - где 0 - целая часть, false означает отсутствие части до периода (которая есть у других дробей, например, у 59/55 = 1,072727272... = (1, 0, 72) часть до периода это "0", отличаем от ситуации, когда её нет совсем, как у 1/3), а период это "3".

По идее, реализация такова:

  • сцепить цифры до периода и период в число $d;
  • получить число $d2, в котором столько девяток, сколько цифр в периоде дроби и затем столько нулей, сколько цифр до периода. Например, для (1, 791, 6) получится 9000, т.к. в периоде одна цифра и три цифры до периода, для (2, false, 72) получится 99, в периоде две цифры, а до периода цифр нет. Мы пользуемся "скользкими" преобразованиями вроде strval(false) и число - false, но на данный момент в PHP 8 они работают корректно;
  • от числа $d отнять часть до периода $b;
  • добавив в уменьшенный числитель $d целую часть $a, полученное значение $d1 делим на $d2, сократив дробь, получаем результат.

Вот написанный несколько второпях код, проверен на локальном хосте XAMPP с PHP8.

<?php
 function fraction ($a, $b, $c) {
  //целая часть, часть до периода, период
  $d = intval(strval($b).strval($c)); //цифры до периода и период числом
  $r = $d - $b;
  $clen = strlen(strval($c));
  $d2 = '';
  $d2 = str_pad($d2,$clen,'9');
  if ($b !== false) {
   $blen = strlen(strval($b));
   $d2 = intval(str_pad($d2,$clen+$blen,'0'));
  }
  $d -= $b;
  $d1 = $a * $d2 + $d;
  $gcd = gmp_gcd($d1, $d2);
  $d1 /= $gcd;
  $d2 /= $gcd;
  return $d1.'/'.$d2;
 }
 echo fraction (2, false, 72); //30/11 - части до периода нет
 echo '<br>'.fraction (5, false, 3); //5 1/3 = 16/3
 echo '<br>'.fraction (1, 791, 6); //43/24 
 echo '<br>'.fraction (0, 6, 428571); //9/14
 echo '<br>'.fraction (1, 0, 72); //59/55 - часть до периода именно "0"
?>

В активном файле php.ini должно быть включено расширение GMP (убрать точку с запятой в строке

;extension=gmp

и перезапустить web-сервер). Узнать, где находится активный файл php.ini можно, выполнив это

<?php
 phpinfo();
?>

и прочитав ответ в строке таблицы "Loaded Configuration File".

При желании легко написать и собственную реализацию функции gcd.

05.12.2021, 17:48 [751 просмотр]


теги: php числа алгоритм

К этой статье пока нет комментариев, Ваш будет первым