PHP: сократить дробь или найти её примерное десятичное представление
Вот здесь я подбирал "близкие" дроби довольно громоздким перебором, зато скрипт может сказать, что дробь 335/1095 отличается от 26/85 менее, чем на 1/1000.
Правда, я не помню, почему исключил из подбора близких дробей числители и знаменатели, равные 10, 100 или 1000.
Чтобы это убрать, достаточно заменить в исходнике строку
if (ch1!=z1 && !(ch1==1 || ch1==10 || ch1==100 || ch1==1000 || z1==1 || z1==10 || z1==100 || z1==1000))
на
if (ch1!=z1)
В приведённом ниже учебном примере стояла более скромная задача - просто сократить дробь, если есть такая возможность (наибольшее число, на которое можно поделить числитель и знаменатель дроби, равно НОД от пары значений (числитель, знаменатель)
). На всякий случай добавлено и "примерное округление", но не такое как в скрипте по ссылке - функция error($er)
просто представляет дробь как число, числитель и знаменатель которого не превышают 10 в степени $er
.
Вот код класса-примера, сделать для него оболочку нетрудно. Обратите внимание, что и cut
, и error
пишут в приватные свойства класса, то есть, значение дроби после их вызова меняется.
<?php class Fraction { //Дробь private $ch,$zn; //Числитель и знаменатель function __construct ($ch=1,$zn=1) { //конструктор $this->ch = abs(intval($ch)); $this->zn = abs(intval($zn)); } function get() { //Вернуть дробь строкой вида "12/34" return ( $this->zn == 0 ? '∞' : ($this->ch==$this->zn ? '1' : $this->ch.'/'.$this->zn) ); } private function nod($ch,$zn) { //Найти НОД return ($ch ? $this->nod($zn%$ch,$ch) : $zn); } function cut() { //Сократить, если есть НОД>1 $nod = $this->nod($this->ch,$this->zn); if ($nod>1) { $this->ch/=$nod; $this->zn/=$nod; } } function dec($signs=3) { //Десятичное представление с $signs знаками в дробной части (округление) return ($this->zn == 0 ? '∞' : round($this->ch/$this->zn,$signs)); } function error($er=1) { //Примерное десятичное представление дробью $er степени десятки ($er>0), вернёт оценку погрешности if ($this->zn == 0) return '∞'; $dec = $this->ch/$this->zn; $dec2 = preg_replace("/^(.*[,\.]\d{0,".$er."}).*$/","$1","$dec"); $this->ch=$dec2*pow(10,$er); $this->zn=pow(10,$er); return round(abs($dec-$this->ch/$this->zn),$er); } } $n = new Fraction(24,36); echo '<br>Исходная дробь: '.$n->get(); $n->cut(); echo '<br>Сокращённая дробь: '.$n->get(); echo '<br>В десятичном виде: '.$n->dec(); $e=$n->error(1); echo '<br>Приблизительно равно: '.$n->get().' с погрешностью '.$e; ?>
Конструктор класса делает переданные в него значения числителя и знаменателя натуральными числами, методы учитывают, что числитель и знаменатель могут совпадать или в знаменателе может оказаться ноль.
Любопытно в коде разве то, как в функции error
оставлено (не округлено) $er
знаков в дробной части числа с помощью стандартной preg_replace
.
Вывод этого примера:
Исходная дробь: 24/36 Сокращённая дробь: 2/3 В десятичном виде: 0.667 Приблизительно равно: 6/10 с погрешностью 0.1
26.02.2016, 20:40 [6807 просмотров]