10 способов получить модуль числа (а может, и больше)

Пишем функцию вычисления модуля числа. Сколько способов существует? Давайте посчитаем!

Всем привет, сразу

DISCLAIMER: Данная статья носит исключительно развлекательный характер, не несет в себе никакой практической пользы и написана только для того, чтобы срубить плюсов just for fun:)

Как-то раз с коллегой зашел разговор о том почему в платформе не реализована функция получения модуля числа, ведь для учетной системы это довольно нужная вещь (скорее всего разработчики платформы еще заняты написанием функции инкрементации и им не до этого, кстати если у вас есть предположения, то пишите в комментариях) и мы обсуждали, что способов написания такой функции может быть несколько и я решил посчитать, а сколько же их можно придумать. Конечно большинство из них "высосаны из пальца" и не могут использоваться на практике в виду здравого смысла, но нас это не останавливает), итак, поехали!

1.Наиболее логичный и распространенный способ, проверяем на превышение нуля и инвертируем значение при необходимости

Функция МодульЧисла1(Число)

Возврат ?(Число >= 0, Число, -Число);

КонецФункции // МодульЧисла()

2.Также довольно распространенный способ, используем функцию Макс()

Функция МодульЧисла2(Число)

Возврат Макс(Число, -Число);

КонецФункции // МодульЧисла()

На этом адекватные способы закончились) и начинаются извращения начинаем использовать

3.Перевести в строку, избавиться от минуса и конвертировать обратно в число?! Легко!

Функция МодульЧисла3(Число)

ЧислоСтрокой = Формат(Число, "ЧРД=.; ЧН=; ЧГ=");
ЧислоСтрокой = СтрЗаменить(ЧислоСтрокой, "-", "");

Возврат Число(ЧислоСтрокой);

КонецФункции // МодульЧисла()

4.Далее вспоминаем, что можем использовать com-объекты, а это открывает нам удивительные возможности

Изначально я использовал такой код:

ЧислоСтрокой = Формат(Число, "ЧРД=.; ЧН=; ЧГ=");
Script = Новый COMОбъект("MSScriptControl.ScriptControl");
Script.Language = "javascript";
Script.Eval(СтрШаблон("var abs = Math.abs(%1);",ЧислоСтрокой));

Возврат Script.CodeObject.abs;

Но в серверном контексте я получил ошибку отсутствия класса из-за различия в разрядности, а делать обертку на корпоративном сервере не хотелось, поэтому я решил использовать другой com, а именно regexp

Функция МодульЧисла4(Число)

RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.Global   = Истина;
RegExp.IgnoreCase  = Истина;
RegExp.Pattern = "d+[.,]?d+";

Matches = RegExp.Execute(Число);
Если Matches.Count() > 0 Тогда
Возврат Число(Matches.Item(0).Value);
Иначе
ВызватьИсключение("Нет вхождения строки");
КонецЕсли;

КонецФункции // МодульЧисла()

5.Используем список значений и сортируем, почему нет?

Функция МодульЧисла5(Число)

СписокЗначений = Новый СписокЗначений;
СписокЗначений.Добавить(Число);
СписокЗначений.Добавить(-Число);
СписокЗначений.СортироватьПоЗначению(НаправлениеСортировки.Убыв);

Возврат СписокЗначений[0].Значение;

КонецФункции // МодульЧисла()

6.Используем запрос, в принципе это нормальный способ и т.к. вычисление производится на стороне СУБД я решил его тоже включить

Функция МодульЧисла6(Число)

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫБОР
|  КОГДА &Число >= 0
|   ТОГДА &Число
|  ИНАЧЕ -&Число
| КОНЕЦ КАК Модуль";

Запрос.УстановитьПараметр("Число", Число);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
ВыборкаДетальныеЗаписи.Следующий();

Возврат ВыборкаДетальныеЗаписи.Модуль;

КонецФункции // МодульЧисла()

7.Далее вспоминаем из курса школьной программы гуглим, что

Модуль числа a – это арифметический квадратный корень из квадрата числа a, исходя из этого пишем функцию

Функция МодульЧисла7(Число)

Квадрат = Pow(Число, 2);
Корень  = Sqrt(Квадрат);

Возврат Корень;

КонецФункции // МодульЧисла()

8.Используем Формат, чтобы избавиться от минуса и используем функцию Вычислить 

Функция МодульЧисла8(Число)

ЧислоСтрокой = Формат(Число, "ЧРД=.; ЧН=; ЧГ=; ЧО=0");
Возврат Вычислить("0+"+ЧислоСтрокой);

КонецФункции 

Да остановись уже!

9.Здесь вообщем то уже читерство, используем ОписаниеТипов с допустимым знаком "+" и если после приведения результат = 0, то инвертируем значение

Функция МодульЧисла9(Число)

ЧислоСтрокой = Формат(Число, "ЧРД=.; ЧН=; ЧГ=");
Подстроки        = СтрРазделить(ЧислоСтрокой, ".");
ЧислоРазрядов     = СтрДлина(Подстроки[0]);
ЧислоРазрядовДробнойЧасти  = 0;
Если Подстроки.Количество() > 1 Тогда
ЧислоРазрядовДробнойЧасти = СтрДлина(Подстроки[1]);
КонецЕсли;
КвалификаторЧисла = Новый КвалификаторыЧисла(ЧислоРазрядов, ЧислоРазрядовДробнойЧасти, ДопустимыйЗнак.Неотрицательный);
ТипЧисло = Новый ОписаниеТипов("Число", КвалификаторЧисла);
Если ТипЧисло.ПривестиЗначение(Число) = 0 Тогда
Возврат -Число;
Иначе
Возврат Число;
КонецЕсли;

КонецФункции // МодульЧисла()

Все? Нет

10.И напоследок используем такой же подход, перехватываем исключение в функции, где параметр положительное число, например, СлучайноеЧисло

Функция МодульЧисла10(Число)

ГСЧ = Новый ГенераторСлучайныхЧисел;
Попытка
СлучайноеЧисло = ГСЧ.СлучайноеЧисло(0, Число);
Возврат Число;
Исключение
Возврат -Число;
КонецПопытки;

КонецФункции 

И в заключение этой "шедевральной" статьи график (обработка во вложении) по скорости выполнения на 10000 итерациях. Версия платформы: 8.3.13.1513

Ожидаемо запрос и com самый медленный ввиду инициализации объектов, а математика самая быстрая.

Знаешь еще способы — пиши в комментах!

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

 

29 Comments

  1. DJDUH
    1.Наиболее логичный и распространенный способ, проверяем на превышение нуля и инвертируем значение при необходимости

    Функция МодульЧисла1(Число)

    Возврат ?(Число >= 0, Число, -Число);

    КонецФункции // МодульЧисла()

    С точки зрения математики

    >=0

    .

    Reply ↓
  2. json

    чисто как еще один способ

    МодульЧисла = Число(СтрЗаменить(СтрЗаменить(Число, «-«, «»), Символ(160), «»));
    Reply ↓
  3. ahahaev

    (1) Либо ?(Число < 0, -Число, Число).

    Чтобы произносить было короче 😀

    Reply ↓
  4. sam441

    (1)Согласен, исправил

    Reply ↓
  5. singlych

    Возврат ?(СтрДлина(Число) > СтрДлина(-Число), -Число, Число)

    Reply ↓
  6. SlavaKron

    (2) Так быстрее:

    МодульЧисла = Число(СтрЗаменить(XMLСтрока(Число), «-«, «»));
    Reply ↓
  7. singlych

    А еще прикольно с БСП, правда только для целых от -99 до 999

    СтроковыеФункцииКлиентСервер.ПреобразоватьЧислоВАрабскуюНотацию(СтроковыеФункцииКлиентСервер.ПреобразоватьЧислоВРимскуюНотацию(Число))

    Reply ↓
  8. SlavaKron
    запрос и com самый медленный ввиду инициализации объектов

    Вы каждую итерацию их инициализировали? Так не пойдёт, такие вещи кэшировать надо.

    Мои результаты на 1 млн. итераций (в мс):

    Число > 0 391

    Макс 393

    СтрЗаменить 4356

    Число(СтрЗаменить(XMLСтрока 2179

    СтрДлина 3873

    Лев 1200

    Sqrt 1115

    Reply ↓
  9. sam441

    (8) Была такая мысль, но мы же пишем независимую функцию, работающую без дополнительных настроек, естественно, я знаю про кэш, да и в контексте «несерьезности» задачи вряд ли это имеет смысл 🙂

    Reply ↓
  10. ildarovich

    Вот два варианта на основе «индикаторной» функции:

    Функция МодульЧисла21(Число)
    
    Возврат ((Число > 0) * 2 — 1) * Число
    
    КонецФункции
    
    Функция МодульЧисла22(Число)
    
    Возврат (Число > 0) * Число — (Число < 0) * Число
    
    КонецФункции

    Показать

    И для разнообразия

    Функция МодульЧисла23(Число)
    
    Возврат — Мин(Число, — Число)
    
    КонецФункции
    Reply ↓
  11. Rustig

    (0) шуточные задачки развивают логическое мышление 🙂

    Reply ↓
  12. acanta

    Все, о чем молчат гусары…

    Reply ↓
  13. user856012

    Неее, это другое: «Баловство это, барин, жениться вам надо…» (с)

    Reply ↓
  14. kredko

    Якубович и Спанчбоб — самые главные персонажи в этой статье.

    Reply ↓
  15. madonov

    Reply ↓
  16. pm74

    шутки ради

    Функция МодульЧисла_00000001(Число)  // для |Число| > 0.00000001
    Возврат -100000000*(Число-(Число+0.00000001)%(Число-0.00000001)-(Число-0.00000001)%(Число+0.00000001))*Число;
    КонецФункции
    
    Reply ↓
  17. user811769

    спасибо, повеселили с утра пораньше =)

    Reply ↓
  18. sam441

    (15) Ну как бы в самом начале написал just for fun)

    Reply ↓
  19. rpgshnik

    Запросы рулят, говорили они 🙂

    Reply ↓
  20. scientes

    Pow(10,0,5*Log10(Число*Число))

    Reply ↓
  21. collider
    Функция МодульЧисла(Число)
    ДобавляемыеРеквизиты = Новый Массив;
    НеотрицательноеЧисло = Новый РеквизитФормы(«НеотрицательноеЧисло», Новый ОписаниеТипов(«Число», , , Новый КвалификаторыЧисла(10, 3, ДопустимыйЗнак.Неотрицательный)));
    ДобавляемыеРеквизиты.Добавить(НеотрицательноеЧисло);
    ИзменитьРеквизиты(ДобавляемыеРеквизиты);
    ЭтаФорма.НеотрицательноеЧисло = Число;
    Возврат ?(ЭтаФорма.НеотрицательноеЧисло = 0, -Число, Число);
    КонецФункции
    Reply ↓
  22. morin

    Для особо искушенных: (x #k8SjZc9Dxk (x >> 31)) — (x >> 31)

    Reply ↓
  23. FesenkoA

    Можно еще создать макет, в котором заполнить все положительные числа, потом в процессе загрузить колонку в массив и проверить на наличие числа в массиве, если нету — умножить на (-1).

    Reply ↓
  24. sam441

    (25)

    Можно еще создать макет, в котором заполнить все положительные числа

    идеально:) какое последнее число?)

    Reply ↓
  25. spacecraft

    (10)

    Возврат (Число > 0) * Число — (Число < 0) * Число

    это можно упростить:

    Возврат (Число*((Число>0)-(Число<0)))
    Reply ↓
  26. FesenkoA

    (26) 99999999999999999999999999999999,99999999999999999999999999999999

    [32,32]

    Reply ↓
  27. FesenkoA

    Опять же, можно воспользоваться АПИ (типа http://mobmath.appspot.com), передать туда уравнение и получить ответ

    Reply ↓
  28. FesenkoA

    Модуль=?(Pow(10, число)>1,1,-1)*число;

    Reply ↓
  29. qwinter

    Какие то жуткие цифры на диаграмме)) Вы не в отладке тест сделали случайно?)) Я советую провести тест без нее и выложить результаты, т.к. первый метод должен выигрывать у второго, пусть и немного.

    Reply ↓

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *