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 не будет опубликован. Обязательные поля помечены *