Недавнее исследование «Использование и атрибуция сниппетов кода Stack Overflow в проектах GitHub» внезапно обнаружило, что чаще всего в опенсорсных проектах встречается мой ответ, написанный почти десять лет назад. По иронии судьбы, там баг.
Еще в 2010 году я сидел в своём офисе и занимался ерундой: развлекался код-гольфингом и накручивал рейтинг на Stack Overflow.
Моё внимание привлёк следующий вопрос: как вывести количество байт в удобочитаемом формате? То есть как преобразовать что-то вроде 123456789 байт в «123,5 МБ».
Старый добрый интерфейс 2010 года, спасибо The Wayback Machine
Неявно подразумевалось, что результатом будет число между 1 и 999,9 с соответствующей единицей измерения.
Уже был один ответ с циклом. Идея простая: проверять все степени с самой большой единицы (ЭБ = 1018 байт) до самой маленькой (Б = 1 байт) и применить первую, которая меньше числа байт. В псевдокоде это выглядит примерно так:
Обычно при наличии правильного ответа с положительной оценкой его трудно догнать. На жаргоне Stack Overflow это называется проблемой самого быстрого стрелка на Западе. Но здесь у ответа было несколько недостатков, поэтому я всё равно надеялся его превзойти. По крайней мере, код с циклом можно значительно сократить.
Тут меня осенило. Приставки кило-, мега-, гига-,… — ни что иное, как степени 1000 (или 1024 в стандарте МЭК), так что правильную приставку можно определить с помощью логарифма, а не цикла.
Основываясь на этой идее, я опубликовал следующее:
Конечно, это не очень читабельно, и log/pow уступает по эффективности другим вариантам. Но никакого цикла и почти нет ветвлений, так что результат получился довольно красивым, на мой взгляд.
Оставалось только подождать и посмотреть, как сообщество воспримет ответ. Я подумать не мог, что этот фрагмент кода станет самым тиражирумым в истории Stack Overflow.
Перенесёмся в 2018 год. Аспирант Себастьян Балтес публикует в научном журнале Empirical Software Engineering статью под названием «Использование и атрибуция сниппетов кода Stack Overflow в проектах GitHub». Тема его исследования — насколько соблюдается лицензия Stack Overflow CC BY-SA 3.0, то есть указывают ли авторы ссылки на Stack Overflow как источник кода.
Для анализа из дампа Stack Overflow были извлечены сниппеты кода и сопоставлены с кодом в публичных репозиториях GitHub. Цитата из реферата:
(Спойлер: нет, большинство программистов не соблюдает требования лицензии).
В статье есть такая таблица:
Этот ответ вверху с идентификатором 3758880 оказался тем самым ответом, который я опубликовал восемь лет назад. На данный момент у него более ста тысяч просмотров и более тысячи плюсов.
Быстрый поиск на GitHub действительно выдаёт тысячи репозиториев с кодом
Поиск этого фрагмента в своём репозитории:
Держу пари, вы уже задумались об этом. Что же за ошибка в коде?
Ещё раз:
Какие варианты?
После эксабайтов (1018) идут зеттабайты (1021). Может, действительно большое число выйдет за границы kMGTPE? Нет. Максимальное значение 263-1 ? 9,2 ? 1018, поэтому никакое значение никогда не выйдет за пределы экзабайт.
Может, путаница между единицами СИ и двоичной системой? Нет. В первой версии ответа была путаница, но её исправили довольно быстро.
Может, exp в конечном итоге обнуляется, вызывая сбой charAt(exp-1)? Тоже нет. Первый if-оператор охватывает этот случай. Значение exp всегда будет не менее 1.
Может, какая-то странная ошибка округления в выдаче? Ну вот наконец…
Решение работает до тех пор, пока не приблизится к 1 МБ. Когда в качестве входных данных задано 999 999 байт, результат (в режиме СИ) —
В своё оправдание могу сказать, что на момент написания такая ошибка была во всех 22 опубликованных ответах, включая Apache Commons и библиотеки Android.
Как это исправить? Прежде всего, отметим, что показатель степени (exp) должен измениться с ‘k’ на ‘M’, как только число байт ближе к 1 ? 1,0002 (1 МБ), чем к 999,9 ? 10001 (999,9 k). Это происходит на 999 950. Точно так же следует переключиться с ‘M’ на ‘G’, когда мы проходим 999 950 000 и так далее.
Вычисляем этот порог и увеличиваем
С этим изменением код работает хорошо до тех пор, пока количество байт не приблизится к 1 ЭБ.
При расчёте 999 949 999 999 999 999 код выдаёт
Теперь мы столкнулись с ограничениями
Проблему представляют два вычисления:
Мы можем переключиться на
Для решения первой проблемы можем уменьшить значение
Для решения второй проблемы нам важны наименее значимые биты (у 99994999...9 и 99995000...0 должны быть разные степени), поэтому придётся найти иное решение.
Сначала отметим, что существует 12 различных пороговых значений (по 6 для каждого режима), и только одно из них приводит к ошибке. Неправильный результат можно однозначно идентифицировать, потому что он заканчивается на D0016. Значит, можно исправить его напрямую.
Поскольку в результатах с плавающей запятой мы полагаемся на определённые битовые шаблоны, то применяем модификатор strictfp для гарантии, что код работает независимо от аппаратного обеспечения.
Неясно, при каких обстоятельствах может иметь смысл отрицательное количество байт, но поскольку в Java нет беззнакового
Напишем
Выражение такое многословное, потому что
Вот окончательная версия кода, сокращённая и уплотнённая в духе оригинальной версии:
Обратите внимание, что это началось как попытка избежать циклов и чрезмерного ветвления. Но после сглаживания всех пограничных ситуаций код стал ещё менее читабельным, чем исходная версия. Лично я бы не стал копировать этот фрагмент в продакшн.
Для обновлённой версии продакшн-качества см. отдельную статью: «Форматирование размера байт в удобочитаемый формат».
Давным-давно…
Еще в 2010 году я сидел в своём офисе и занимался ерундой: развлекался код-гольфингом и накручивал рейтинг на Stack Overflow.
Моё внимание привлёк следующий вопрос: как вывести количество байт в удобочитаемом формате? То есть как преобразовать что-то вроде 123456789 байт в «123,5 МБ».
Старый добрый интерфейс 2010 года, спасибо The Wayback Machine
Неявно подразумевалось, что результатом будет число между 1 и 999,9 с соответствующей единицей измерения.
Уже был один ответ с циклом. Идея простая: проверять все степени с самой большой единицы (ЭБ = 1018 байт) до самой маленькой (Б = 1 байт) и применить первую, которая меньше числа байт. В псевдокоде это выглядит примерно так:
suffixes = [ "EB", "PB", "TB", "GB", "MB", "kB", "B" ]
magnitudes = [ 10^18, 10^15, 10^12, 10^9, 10^6, 10^3, 10^0 ]
i = 0
while (i < magnitudes.length && magnitudes[i] > byteCount)
i++
printf("%.1f %s", byteCount / magnitudes[i], suffixes[i])
Обычно при наличии правильного ответа с положительной оценкой его трудно догнать. На жаргоне Stack Overflow это называется проблемой самого быстрого стрелка на Западе. Но здесь у ответа было несколько недостатков, поэтому я всё равно надеялся его превзойти. По крайней мере, код с циклом можно значительно сократить.
Это ж алгебра, всё просто!
Тут меня осенило. Приставки кило-, мега-, гига-,… — ни что иное, как степени 1000 (или 1024 в стандарте МЭК), так что правильную приставку можно определить с помощью логарифма, а не цикла.
Основываясь на этой идее, я опубликовал следующее:
public static String humanReadableByteCount(long bytes, boolean si) {
int unit = si ? 1000 : 1024;
if (bytes < unit) return bytes + " B";
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
Конечно, это не очень читабельно, и log/pow уступает по эффективности другим вариантам. Но никакого цикла и почти нет ветвлений, так что результат получился довольно красивым, на мой взгляд.
Математика тут нехитрая. Количество байт выражается как byteCount = 1000s, где s представляет степень (в двоичной нотации база 1024.) Решение s дает s = log1000(byteCount).
В API нет простого выражения log1000, но мы можем выразить его в терминах натурального логарифма следующим образом s = log(byteCount) / log(1000). Затем преобразуем s в int, так что если у нас, например, более одного мегабайта (но не полный гигабайт), то в качестве единицы измерения будет использоваться МБ.
Получается, что если s = 1, то используется размерность килобайт, если s = 2 — мегабайт и так далее. Делим byteCount на 1000s и шлёпаем соответствующую букву в префикс.
Оставалось только подождать и посмотреть, как сообщество воспримет ответ. Я подумать не мог, что этот фрагмент кода станет самым тиражирумым в истории Stack Overflow.
Исследование по атрибуции
Перенесёмся в 2018 год. Аспирант Себастьян Балтес публикует в научном журнале Empirical Software Engineering статью под названием «Использование и атрибуция сниппетов кода Stack Overflow в проектах GitHub». Тема его исследования — насколько соблюдается лицензия Stack Overflow CC BY-SA 3.0, то есть указывают ли авторы ссылки на Stack Overflow как источник кода.
Для анализа из дампа Stack Overflow были извлечены сниппеты кода и сопоставлены с кодом в публичных репозиториях GitHub. Цитата из реферата:
Представляем результаты крупномасштабного эмпирического исследования, анализирующего использование и атрибуцию нетривиальных фрагментов кода Java из ответов SO в публичных проектах GitHub (GH).
(Спойлер: нет, большинство программистов не соблюдает требования лицензии).
В статье есть такая таблица:
Этот ответ вверху с идентификатором 3758880 оказался тем самым ответом, который я опубликовал восемь лет назад. На данный момент у него более ста тысяч просмотров и более тысячи плюсов.
Быстрый поиск на GitHub действительно выдаёт тысячи репозиториев с кодом
humanReadableByteCount
.Поиск этого фрагмента в своём репозитории:
$ git grep humanReadableByteCount
Забавная история, как я узнал об этом исследовании.
Себастьян нашёл совпадение в репозитории OpenJDK без какой-либо атрибуции, а лицензия OpenJDK не совместима с CC BY-SA 3.0. В списке рассылки jdk9-dev он спросил: это код Stack Overflow скопирован из OpenJDK или наоборот?
Самое смешное то, что я как раз работал в Oracle, в проекте OpenJDK, поэтому мой бывший коллега и друг написал следующее:
Привет,
Почему бы не спросить напрямую у автора этого сообщения на SO (aioobe)? Он является участником OpenJDK и работал в Oracle, когда этот код появился в исходных репозиториях OpenJDK.
Oracle очень серьёзно относится к таким вопросам. Я знаю, что некоторые менеджеры вздохнули с облегчением, когда прочитали этот ответ и нашли «виновника».
Затем Себастьян написал мне, чтобы прояснить ситуацию, что я и сделал: этот код добавили ещё до моего прихода в Oracle и я не имею отношения к коммиту. С Oracle лучше не шутить. Через пару дней после открытия тикета этот код был удалён.
Баг
Держу пари, вы уже задумались об этом. Что же за ошибка в коде?
Ещё раз:
public static String humanReadableByteCount(long bytes, boolean si) {
int unit = si ? 1000 : 1024;
if (bytes < unit) return bytes + " B";
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
Какие варианты?
После эксабайтов (1018) идут зеттабайты (1021). Может, действительно большое число выйдет за границы kMGTPE? Нет. Максимальное значение 263-1 ? 9,2 ? 1018, поэтому никакое значение никогда не выйдет за пределы экзабайт.
Может, путаница между единицами СИ и двоичной системой? Нет. В первой версии ответа была путаница, но её исправили довольно быстро.
Может, exp в конечном итоге обнуляется, вызывая сбой charAt(exp-1)? Тоже нет. Первый if-оператор охватывает этот случай. Значение exp всегда будет не менее 1.
Может, какая-то странная ошибка округления в выдаче? Ну вот наконец…
Много девяток
Решение работает до тех пор, пока не приблизится к 1 МБ. Когда в качестве входных данных задано 999 999 байт, результат (в режиме СИ) —
"1000,0 kB"
. Хотя 999 999 ближе к 1000 ? 10001, чем к 999,9 ? 10001, сигнификант 1000 запрещён спецификацией. Правильный результат — "1.0 MB"
.В своё оправдание могу сказать, что на момент написания такая ошибка была во всех 22 опубликованных ответах, включая Apache Commons и библиотеки Android.
Как это исправить? Прежде всего, отметим, что показатель степени (exp) должен измениться с ‘k’ на ‘M’, как только число байт ближе к 1 ? 1,0002 (1 МБ), чем к 999,9 ? 10001 (999,9 k). Это происходит на 999 950. Точно так же следует переключиться с ‘M’ на ‘G’, когда мы проходим 999 950 000 и так далее.
Вычисляем этот порог и увеличиваем
exp
, если bytes
больше:if (bytes >= Math.pow(unit, exp) * (unit - 0.05))
exp++;
С этим изменением код работает хорошо до тех пор, пока количество байт не приблизится к 1 ЭБ.
Ещё больше девяток
При расчёте 999 949 999 999 999 999 код выдаёт
1000.0 PB
, а правильный результат 999.9 PB
. Математически код точен, так что же здесь происходит?Теперь мы столкнулись с ограничениями
double
.Введение в арифметику с плавающей запятой
Согласно спецификации IEEE 754, у близких к нулю значений с плавающей запятой очень плотное представление, а у больших значений — очень разреженное. На самом деле, половина всех значений находится между -1 и 1, а когда речь идёт о больших числах, значение размеромLong.MAX_VALUE
ничего не значит. В прямом смысле.
double l1 = Double.MAX_VALUE; double l2 = l1 - Long.MAX_VALUE; System.err.println(l1 == l2); // prints true
Подробнее см. «Биты значения с плавающей запятой».
Проблему представляют два вычисления:
- Деление в аргументе
String.format
и
- Порог для наращивания
exp
Мы можем переключиться на
BigDecimal
, но это скучно. Кроме того, здесь тоже возникают проблемы, потому что в стандартном API нет логарифма для BigDecimal
.Уменьшение промежуточных значений
Для решения первой проблемы можем уменьшить значение
bytes
до нужного диапазона, где точность лучше, и соответственно настроить exp
. Конечный результат в любом случае округляется, поэтому неважно, что мы выбрасываем наименее значимые разряды.if (exp > 4) {
bytes /= unit;
exp--;
}
Настройка наименее значимых битов
Для решения второй проблемы нам важны наименее значимые биты (у 99994999...9 и 99995000...0 должны быть разные степени), поэтому придётся найти иное решение.
Сначала отметим, что существует 12 различных пороговых значений (по 6 для каждого режима), и только одно из них приводит к ошибке. Неправильный результат можно однозначно идентифицировать, потому что он заканчивается на D0016. Значит, можно исправить его напрямую.
long th = (long) (Math.pow(unit, exp) * (unit - 0.05));
if (exp < 6 && bytes >= th - ((th & 0xFFF) == 0xD00 ? 52 : 0))
exp++;
Поскольку в результатах с плавающей запятой мы полагаемся на определённые битовые шаблоны, то применяем модификатор strictfp для гарантии, что код работает независимо от аппаратного обеспечения.
Отрицательные значения на входе
Неясно, при каких обстоятельствах может иметь смысл отрицательное количество байт, но поскольку в Java нет беззнакового
long
, лучше обработать такой вариант. Прямо сейчас ввод вроде -10 000 выдаёт -10000 B
.Напишем
absBytes
:long absBytes = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
Выражение такое многословное, потому что
-Long.MIN_VALUE == Long.MIN_VALUE
. Теперь мы выполняем все вычисления exp
, используя absBytes
вместо bytes
.Окончательная версия
Вот окончательная версия кода, сокращённая и уплотнённая в духе оригинальной версии:
// From: https://programming.guide/the-worlds-most-copied-so-snippet.html
public static strictfp String humanReadableByteCount(long bytes, boolean si) {
int unit = si ? 1000 : 1024;
long absBytes = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
if (absBytes < unit) return bytes + " B";
int exp = (int) (Math.log(absBytes) / Math.log(unit));
long th = (long) (Math.pow(unit, exp) * (unit - 0.05));
if (exp < 6 && absBytes >= th - ((th & 0xfff) == 0xd00 ? 52 : 0)) exp++;
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
if (exp > 4) {
bytes /= unit;
exp -= 1;
}
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
Обратите внимание, что это началось как попытка избежать циклов и чрезмерного ветвления. Но после сглаживания всех пограничных ситуаций код стал ещё менее читабельным, чем исходная версия. Лично я бы не стал копировать этот фрагмент в продакшн.
Для обновлённой версии продакшн-качества см. отдельную статью: «Форматирование размера байт в удобочитаемый формат».
Ключевые выводы
- В ответах на Stack Overflow могут быть ошибки, даже если у них тысячи плюсиков.
- Проверьте все граничные случаи, особенно в коде со Stack Overflow.
- Арифметика с плавающей запятой сложна.
- Обязательно указывайте правильную атрибуцию при копировании кода. Кто-то может вывести вас на чистую воду.
mikhailian
Оригинальный вариант кода, пусть и неправильный, был красив. А после всех перипетий получилось помoище.
c_kotik
Не могу не спросить — вам шашечки или ехать?
extempl
Мне кажется, этот комментарий на 100% можно развернуть в обратную сторону.
Раньше код "ехал" — выполнял что должен выполнять в 99.9999999% случаев и если где-то проскакивало 1000КБ — то было это при выводе на экран и в общем никого не колыхало (ничего не могло сломать).
Теперь это не только "ехать", но ещё и "шашечки", которые, как-бы, и не очень-то были нужны (для "ехать").
WhiteBlackGoose
Более того, всегда можно вернуться к циклу.
HelpOP
Нельзя. Тут в дело вступают законы квантовой физики. Пока ошибка не найдена код можно использовать, как только ошибка найдена код не подлежит использованию.
Вы же не будете пытаться играть с мертвым котом?
ardraeiss
А если Вы биолог? Или некромант с наномашинами/испытатель экзоскелета...
kisskin
Если знакомест было 3, а получили 4, то это могло ввести заблуждение 100 вместо 1000, например
mayorovp
Там же в строку потом единица измерения приписывается. Скорее потеряется буква "б", чем нолик из середины строки.
DistortNeo
Скорее уж, "1000." вместо "1000.0". Впрочем, учитывая, что возвращается строка вместе с единицей измерения, выше риск, что затрётся последняя буква. Или, что хуже, потеряется нулевой символ при использовании буфера фиксированного размера.
mayorovp
Это ж Java, о каком нулевом символе речь?
ardraeiss
Красивый бажный код подобен помоищному бажному коду, только с красотой.
Ну да, не хватает, например, кратких поясняющих комментариев, которые разобьют исправленный код на куда более легко воспринимаемые сегменты — и тем сделают его красивым. Но — он уже без бага, а исходная красота всё равно с оным.
bm13kk
хуже. В этом коде захардкоджена борьба с протекшей абстракцией. И захаркоджено так, что если ты его не написал — не разберешься.
ardraeiss
Кстати, сам рассматриваемый в статье ответ на SO теперь тоже исправлен — и там вообще другая версия предложена, более грациозная:
В статье же, таким образом, остался поучительный пример исправление красивого выглядящего правильным кода.
Romaboy
А я искренне не понимаю чем цикл не устроил, там хоть и магнитуды автор рандомные указал, но исправить очень легко и работало бы без багов.
Оригинальный вариант с логарифмом ужасен, не настолько как в финале, но все же.
Предлагаю на собеседованиях если человек четко может дать определение логарифма — отсеивать, пусть математики вселенную изучают, а не код пишут.
ainoneko
Arris
С иронией: замеряли-то небось в мирное время? :)
S-trace
Вы про повреждения от попаданий снарядов и бомб?
Кстати, подобное исследование было бы действительно интересным — по какой именно математической формуле муравьи восстанавливают повреждённые муравейники — снова приводят их к круглому конусу, или же получается некая сглаженная пирамида с основанием в виде невыпуклого многоугольника?)
AndrewRo
Я думаю, имеется в виду бородатый анекдот:
S-trace
Я помню этот анекдот, но вопрос поведения муравьёв после разрушения муравейника для меня более интересен оказался)
Tamerlan666
Справедливости ради, МАН — это школьная "академия". Для школьников такое "открытие" вполне простительно.
Vitaly83vvp
Да, тут сложно не согласиться.
На мой взгляд, достаточно было бы просто 10^n заменить на 2^n.
tangro
Добро пожаловать в разработку библиотечного кода! Пишешь красивую реализацию чего-то, приходит 100500 человек, которые показывают тебе, что на вышедшем 100 лет назад железе, на Северном Полюсе, когда Луна в Водолее твой код не работает. И требуют исправлений. И ты исправляешь, потому что это же библиотека, должна работать везде.
402d
И что обидно, чаще такое оформляется не пулл реквестом, а исуей.
Так, что ребята аккуратнее с публикацией опенсорса. Люди по дефолту
считают, что Вы теперь обязаны пожизненно сопровождать свой код бесплатно.
S-trace
А как вы считаете, правильнее публиковать исправление очевидной и воспроизводимой (для тебя, на твоём железе) проблемы пулл-реквестом, или же иссуей + пулл-реквестом, фиксящим эту иссую и ссылающимся на эту иссую?
Я вот не так уж давно опубликовал 3 таких вот иссуи с фиксами в одну промышленную (!) библиотеку, но до сих пор ни один из пулл-реквестов не принят, а откомментирован разработчиками лишь одна из трёх иссуй, и ни один из реквестов.
402d
Я в этой статье увидел подтверждение своему отношения к коду с оверфлоу.
Вам дан только пример для идеального случая, который показывает суть как надо решать
задачу. И то, что его всегда надо допиливать тем, что автор вынес за скобки
для простоты понимания сути.
Не надо его в лоб копировать в свои проекты.
lopatoid
А я в этой статье увидел подтверждение своему отношения к коду с оверфлоу.
Я бы сам написал код не лучше, чем первый вариант ответа, то есть тоже с багом. И уж точно хуже, чем текущий вариант, без ошибки. По сути использование кода со SO ничем не отличается использованием сторонних библиотек. Да, там могут быть ошибки, ну так они везде могут быть, даже в самом процессоре.
samhuawey
Почему не надо? Скопировал, накатал unit-тест и пользуйся на здоровье.
fougasse
Осталось самая малость — правильный юнит-тест.
Со всеми кейсами типа 999 950 -> 1МБ и прочих 999 949 999 999 999 999.
Arris
Не забудьте только взять unit-тест тоже со StackOverflow. Тогда точно-точно все будет работать. Всегда. Без вопросов. :)
pin2t
Интересная история
PqDn
я думал самый простой и эффективный способ это битовый сдвиг
romanshuvalov
Код не о делении на 2^20, а об определении той единицы измерения, при которой число станет удобно читаемым.
Revertis
Да, получилось реально помоище. Куча неявной математики и странных magic number'ов.
Лучше бы кучу IF'ов написал.
ardraeiss
В исходном исправленном комментарии SO именно куча троичных операторов устроена.
Revertis
Я видел, не слепой. И читаемость у них хуже, чем у IF'ов.
DaleMartinWatson
В данном конкретном случае не хуже, а наоборот. Если раскорячить этот код в три раза, более понятным он не станет.
Fedorkov
Напомнило: Почти во всех реализациях двоичного поиска и сортировки слиянием есть ошибка
maxzhurkin
Так-то можно было перевести всё к интервалу 1-unit, а к логарифму поправочку прибавить (возможно, отрицательную — лень думать, простите) — получилось бы гораздо элегантнее, IMHO
kunix
Вариант c циклом четкий, красивый, обозримый.
Его корректность легко доказать.
Я бы еще оттуда убрал вещественную арифметику, оставив только целые числа.
И убрал выход за пределы массива при нуле байт :)
sanyaa
StackOverflow уже больше десяти лет в обед, могли бы и пораньше сделать выводы о том, что «В ответах на Stack Overflow могут быть ошибки, даже если у них тысячи плюсиков.».
Hab_Reader
… а в соседней теме пишут, что не только называть говнокод говнокодом, но и просто критиковать чужой код — является «токсичностью», противоречащей корпоративным нормам.
S-trace
"Токсичность" — имхо, само определение этого слова противоречит изначальной сути Интернета. И очень многое в Интернете делается под эгидой борьбы с этой "токсичностью".
Пчёлы против мёда.
ImidgX
:-O
Тут же всего лишь шесть шагов, зачем логарифмы считать?! Когда можно просто IF'ами сделать.
А если ещё и с середины сравнивать, то результат вообще за пару сравнений найти.
CoolMind
С удивлением узнал о таком коде. По тегу java вы легко найдёте гораздо более популярные вопросы и ответы. Похоже, автор имел в виду только свой популярный код.
Bringoff
Популярность мерялась не плюсиками на SO, а появлениями этого фрагмента кода в коде проектов на Github.
barbanel
Удивлен что этот код нейросеть не прикрутили =)
kozar
Индивидуально конечно, но лично мне и первый вариант не кажется красивым и хорошим. Нагромождение конструкций, в котором сходу не поймёшь, как он себя ведёт в предельных случаях. Я бы предпочёл что-то вроде такого:
(просто иллюстрация, не обязательно соответствует всем стандартам)
S-trace
<sarcasm>У вас код не соответствует идеологии структурного программирования!</sarcasm>
dididididi
Этот код еще не будет работать, если электричество отключили.
pankraty
Напомнило о баге, который я репортил в Гитлаб, когда на коммит, сделанный 14 декабря, 15 марта пишется "2 months ago". Тоже небось со StackOverflow взяли пример, где автор не учел несколько пограничных случаев…
dax
Ну и вишенка на торте: версия с циклом выполняется быстрее варианта с логарифмом, т.к. имеет асимптотику О(n), где n — количество цифр.
en.wikipedia.org/wiki/Computational_complexity_of_mathematical_operations