Помнится, как-то samsoir, один из core-разработчиков Kohana, задал на официальном форуме задачку: привел кусок кода и попросил найти слабые места в нем (дыры в безопасности, пути оптимизации в целом). Мне понравилась эта идея и вот я попробую открыть аналогичный цикл в моем блоге.
Итак, вот небольшой класс, взятый отсюда (привет, rafi!):
class Num extends Kohana_Num { /** * Returns a human readble number * * @param int a number * @param int thousands * @return string */ public static function human($val, $thousands = 0) { if($val >= 1000) { $val = Num::human($val / 1000, ++$thousands); } else { $unit = array('','k','mil','t','p','e','z','y'); $val = round($val,2) . ' ' . $unit[$thousands]; } return $val; } } // End Num |
Что, по-вашему, тут стоит исправить?
PS. Дабы не плодить гигантские портянки с кодом в комментариях, размещайте ваши варианты на соответствующих сервисах типа http://pastie.org или http://pastebin.com.
не совсем понятно с array(»,’k',’mil’,'t’,'p’,'e’,'z’,'y’)
я бы решал эту задачу без рекурсии
http://pastie.org/1011749
Навскидку — предполагаю, что этот код будет выполняться бесконечно
но хорошо, одна проблема обнаружена, это нежелательная рекурсия.
@php code
Для таких вещей [$num = $num / 1000;] правильнее использовать сокращенную запись [$num /= 1000;].
@biakaveron
Кодить лень – предполагаю, что код и *rafi*, и *php code* не работает с отридцательными числами.
Ну, насчет «правильнее» я не соглашусь — это просто короче
А кодить совсем необязательно. В принципе, обсуждается алгоритм, так что можно и на словах. Замечание по поводу отрицательных чисел принято.
Это не «просто короче» — это интуитивнее, читабильнее и .. короче Чем меньше нагромождение дублируемых кусков кода, тем меньше ошибок.
Не соглашусь. Полная версия выглядит понятнее, про дублирование в данном случае говорить как-то неуместно, нет? Хотя конечно это не означает, что я не использую подобные «сокращалки»
ну, хз .. ИМХО, лаконичность кода — отражает и знаниие языка(ов), и опыт его использования. (это я как TeamLead маленько понудил )
а про дублирование — в слове из 3-х букв (при особом умении) можно сделать 3-и ошибки .. которые кому-то придется искать и исправлять. с другой стороны — использование специфических особенностей языка(ов) делает код менее читабельным для noob’ов.
PS: как обычно каждый останется при своем
Как заметил stalker, отрицательные числа не учитываются. Проверять нужно модуль числа. Так же, нужно исключить числа, что будут больше предлагаемого хелпером диапазона (>=10^23).
версия с проверкой и минус рекурсия
@avis
1. в версии без рекурсии параметр $thousands лишний.
2. я бы запомнил знак числа и abs($val) в начале функции, и везде использовал только $val. а вернул: return ($sign * $val);
PS: но (2) из области оптимизации, которую еще необходимо тестировать на производительность.
Предложу свой вариант:
1. Учитываем размерность массива с единицами измерений
2. Работаем и с отрицательными величинами
3. Отбрасываем рекурсию
4. Проверяем входные параметры (все врут (с))
5. Добавил параметр $step, так сказать на будущее.
Вообще напрашивается создание некоего полуабстрактного метода с километром параметров (начальное смещение $thousands, шаг $step, единицы измерения $units), и отдельных специализированных методов типа human_thousands(), human_bits() и т.д. Например, для физических величин (давление, скорость и т.д.) мы ведь не будем каждый раз писать новые методы с одним и тем же алгоритмом? Кстати, можно добавить и мультиязычность — обернуть значения из $units в вызов __().
@stalker
Полагаю, что подобная оптимизация из разряда «на спичках».
@biakaveron
ага, это зависит от частоты использования данной функции. имеет смысл только при выводе массивов 100k+ значений просто, когда часто работаешь с высоконагруженными системами начинаешь везде использовать «оптимизацию на спичках».
В целом — отличная тема вести такие практикумы. И мозговую деятельность людям позволяет стимулировать и элементы краудсорсинга могут стать полезным для автора.
Нужно бы сделать такую тему для всего kohana сообщества…
Если вспомнить, что log10 — это число цифр в числе минус 1, то получается вот такой код:
$unit = array(», ‘k’, ‘mil’, ‘t’, ‘p’, ‘e’, ‘z’, ‘y’);
$thousands = (int) floor(log10(abs($val)) / 3);
return ($thousands < count($unit))
? round($val / pow(10, $thousands * 3), 2).' '.$unit[$thousands]
: (string) $val;
@Алексей
Ну, не совсем конечно число цифр (если только после округления в меньшую сторону), но вариант весьма интересных хотя бы своей нетривиальностью. Жалко, что если я напишу такой код, то через полгода придется потратить полчасика, чтобы «вкурить», что это я там написал Но уже сам по себе уход от циклов (не говоря про рекурсию) впечатляет.
Кстати, посмотрел в код Ko3, метод
text::bytes()
— там тоже логарифм используется.@biakaveron
Для вывода чисел логарифмы — самое то. Особенно при построении графиков, если нужно подобрать круглый шаг (5, 10, 20, 100 и т.д.) для подписей на осях.