Имя: Пароль:
1C
1С v8
Функция Банковское округление
,
0 alex44ru
 
31.10.18
14:27
Недавно озадачили получать число банковским округлением. На скорую руку родил функцию.

Функция ПолучитьБанковскоеОкругление(Число, Разрядность)Экспорт
    
    Число = Формат(Число,"ЧГ=0");
    СтрокаЧисел = "";
    Для Индекс = 1 По СтрДлина(Число) Цикл    
        Символ = Сред(Число, Индекс, 1);
        Если КодСимвола(Символ) = 44 Тогда
            Для Сч = 0 По Разрядность Цикл
                Символ = Сред(Число, Индекс, 1);
                СтрокаЧисел = СтрокаЧисел + Символ;
                Индекс = Индекс + 1;
            КонецЦикла;
            Если Число(Символ)%2 Тогда
                Возврат Окр(Число(Число), Разрядность, РежимОкругления.Окр15как20);
            КонецЕсли;
            СледСивол = Сред(Число, Индекс, 1);
            Если КодСимвола(СледСивол) <= 53 Тогда        
                Возврат Число(СтрокаЧисел);
            Иначе
                Возврат Окр(Число(Число), Разрядность, РежимОкругления.Окр15как20);
            КонецЕсли;
        Иначе
            СтрокаЧисел = СтрокаЧисел + Символ;
        КонецЕсли;    
    КонецЦикла;
    
КонецФункции

Просто оставлю это здесь, может кому то сбережет время. За критику буду благодарен.
1 Волшебник
 
31.10.18
14:29
а если там не запятая, а десятичная точка?
функция - говно
2 Fragster
 
гуру
31.10.18
14:30
Функция ПолучитьБанковскоеОкругление(Число, Разрядность)Экспорт
    Возврат Окр(Число/2,Разрядность)*2
КонецФункции
3 Fragster
 
гуру
31.10.18
14:31
воспользовался википедией:
Банковское округление (англ. banker's rounding) — округление для этого случая происходит к ближайшему чётному, то есть 2,5 → 2; 3,5 → 4.
4 1Сергей
 
31.10.18
14:31
//Если КодСимвола(СледСивол) <= 53 Тогда
Если СледСивол <= "5" Тогда
5 Fragster
 
гуру
31.10.18
14:32
а, понял
6 Hans
 
31.10.18
14:33
По тру кодингу "Возврат" должен быть только в конце?
7 alex44ru
 
31.10.18
14:36
(2) блин а чего так можно что ли было )))
вот это я путём не тем пошел
ну да и ладно, другие не заблудятся
спасибо Ваше решение намного оптимальнее моего
8 Базис
 
naïve
31.10.18
14:36
(3) А я думал, что в случайный момент сумма обнуляется.

(6) Нет, это нарушает эффективность и добавляет код.
9 alex44ru
 
31.10.18
14:42
(2) как Вы так слёту решили это, Вы знали?
10 Fragster
 
гуру
31.10.18
14:42
Возврат Окр(Число, Разрядность, ?(Число / Pow(10, -разрядность) % 2 < 1, РежимОкругления.Окр15как10, РежимОкругления.Окр15как20))
11 Fragster
 
гуру
31.10.18
14:42
(9) в (2) неправильно, я определение неправильно прочитал. в (10) правильно
12 Fragster
 
гуру
31.10.18
14:43
протестировал для
Число = 3.5;
Разрядность = 0;
Число = 2.5;
Разрядность = 0;

Число = 2.505;
Разрядность = 2;

Число = 2.515;
Разрядность = 2;
13 alex44ru
 
31.10.18
14:44
(10) я уже запутался
14 Вафель
 
31.10.18
14:45
банквоское - это
1.53 =2
1.52 = 1
так?
15 Fragster
 
гуру
31.10.18
14:46
(14) я понял,что банковское, это 2.5 -> 2, 3.5 -> 4
16 Fragster
 
гуру
31.10.18
14:48
единственное, может быть для отрицательных чисел нужно поправить. в любом случае вот как раз для этого нужно юнит тестирование и с ним будет прям просто.
17 Вафель
 
31.10.18
14:48
РежимОкругления.Окр15как10 - это не то самое?
18 Fragster
 
гуру
31.10.18
14:48
(17) нет, так 3.5 будет 3
19 Fragster
 
гуру
31.10.18
14:48
собственно, см. 10, там правильно
20 Злопчинский
 
31.10.18
14:54
Банковское - это когда по четным дням округляют в большую сторону, а по нечетным дням округляют в меньшую..
21 alex44ru
 
31.10.18
14:59
у меня в задании было написано так:

Округление суммы осуществляется по результату
умножения (применяется округление к ближайшему четному (банковское) -
округляется до 2-го знака в зависимости от 3-го знака. Например, число 0,785
округляется до 0,78)
22 Fragster
 
гуру
31.10.18
15:01
ну в общем в (10) правильно все, а те, кто определение (21) писал - чудаки
23 Fragster
 
гуру
31.10.18
15:02
больше бы тесткейсов набросали, все было бы понятно
24 Fragster
 
гуру
31.10.18
15:02
что 0,775 до 0,78, а 0,765 - до 0,76
25 alex44ru
 
31.10.18
15:03
(22) чудаки чудаками, но я вынужден подстраиваться под них
26 Fragster
 
гуру
31.10.18
15:04
(25) ну вот за (10) мне как-нибудь проставишься
27 alex44ru
 
31.10.18
15:05
(26) физмат закончил? у меня только один взгляд на эту функцию вызывает взрыв мозга
28 Fragster
 
гуру
31.10.18
15:06
(27) компьютерных технологий и управления. на самом деле если писать не в одну строку, то понятнее.
29 Fragster
 
гуру
31.10.18
15:07
кстати, Число / Pow(10, -разрядность) % 2 можно заменить на Число * Pow(10, разрядность) % 2
30 alex44ru
 
31.10.18
15:10
(29) только что ткнули носом
есть сумма 20 827,52 её надо умножить на коэф 1.03
получим 21452,3456 после округления должно стать 21452,34
а по твоей формуле (10) получается 21452,35 а вот по формуле (2) норм
31 Дмитрий
 
31.10.18
15:11
Банковское это если пеня за просроченный кредит - округляют в большую сторону, а если процент по депозиту - в меньшую )
32 Fragster
 
гуру
31.10.18
15:13
(30) нет. 21452,345 должно стать 21452,34 - оно и становится. а 21452,3456 должно стать 21452,35
33 Fragster
 
гуру
31.10.18
15:13
если хочется, чтобы получилось 21452,34 предварительно нужно получить с точностью на 1 знак больше
34 alex44ru
 
31.10.18
15:14
(32) я все понимаю но у меня в задании так (21)
35 Fragster
 
гуру
31.10.18
15:14
например Цел(Число * Pow(10, разрядность+1)) / Pow(10, разрядность)
36 Fragster
 
гуру
31.10.18
15:16
в одной строке:
Результат = Окр(Цел(Число * Pow(10, разрядность + 1)) / Pow(10, разрядность + 1), Разрядность, ?(Число * Pow(10, разрядность) % 2 < 1, РежимОкругления.Окр15как10, РежимОкругления.Окр15как20));
37 Fragster
 
гуру
31.10.18
15:16
вот для этого и нужно юнит тестирование, повторюсь
38 alex44ru
 
31.10.18
15:17
(37) оставлю тогда пока как у меня, пусть страшно смотрится, зато считает как требуют
39 Fragster
 
гуру
31.10.18
15:18
(38) ну, если требования формализовать нормально, то все будет считать правильно, да и проверить можно.
40 Fragster
 
гуру
31.10.18
15:18
пока ошибки в (36) с учетом (30) нет
41 Fragster
 
гуру
31.10.18
15:18
тесты пройдены
42 Fragster
 
гуру
31.10.18
15:19
все, что были до этого + случай из (30)
43 alex44ru
 
31.10.18
15:20
(42) как ты это делаешь ))), тебе бы конфигурации прикладные в 1С писать
44 Fragster
 
гуру
31.10.18
15:22
в 4 строки:

ОбрезанноеЧисло = Цел(Число * Pow(10, разрядность + 1)) / Pow(10, разрядность + 1);
ЧислоДляРежимаОкругления = Число * Pow(10, разрядность);
НужныйРежимОкругления = ?(ЧислоДляРежимаОкругления % 2 < 1, РежимОкругления.Окр15как10, РежимОкругления.Окр15как20);
Возврат Окр(ОбрезанноеЧисло, Разрядность, НужныйРежимОкругления);
45 Fragster
 
гуру
31.10.18
15:30
Кстати, ЧислоДляРежимаОкругления возможно нужно тоже получать из ОбрезанноеЧисло, а не из Число
46 alex44ru
 
31.10.18
15:35
(45) я уже давно запутался и не понимаю написанного тут, но тебе верю, расчёты показывают, что алгоритм считает как надо, но будем проверять
47 Fragster
 
гуру
31.10.18
15:37
(46) лично я запутался в (0) да и работать с числами как со строками ИМХО странно
48 alex44ru
 
31.10.18
15:38
(47) в итоге сделал так:

    ОбрезанноеЧисло = Цел(Число * Pow(10, разрядность + 1)) / Pow(10, разрядность + 1);
    ЧислоДляРежимаОкругления = ОбрезанноеЧисло * Pow(10, разрядность);
    НужныйРежимОкругления = ?(ЧислоДляРежимаОкругления % 2 < 1, РежимОкругления.Окр15как10, РежимОкругления.Окр15как20);
    Возврат Окр(ОбрезанноеЧисло, Разрядность, НужныйРежимОкругления);
49 alex44ru
 
31.10.18
15:40
(47) я тяжело работаю с различными функциями над числами, видать мой мозг как у программера сложился в юности, когда я программировал для Z80 прямо в ассемблере, там функций работы над числами не было, в основном сложение, вычитание и бинарные
50 PR
 
31.10.18
15:41
(10) Я бы написал так

Если Окр(Число, Разрядность, РежимОкругления.Окр15как10) = Окр(Число, Разрядность, РежимОкругления.Окр15как20) Тогда
    РежимОкругленияЧисла = РежимОкругления.Окр15как20;
Иначе
    
    ПоловинаОкругленногоЧисла = Окр(Число, Разрядность, РежимОкругления.Окр15как10) / 2;
    
    Если ПоловинаОкругленногоЧисла = Окр(ПоловинаОкругленногоЧисла, Разрядность, РежимОкругления.Окр15как10) Тогда
        РежимОкругленияЧисла = РежимОкругления.Окр15как10;
    Иначе
        РежимОкругленияЧисла = РежимОкругления.Окр15как20;
    КонецЕсли;
    
КонецЕсли;

Возврат Окр(Число, Разрядность, РежимОкругленияЧисла);
51 Fragster
 
гуру
31.10.18
15:42
(50) а зачем тут первая ветка? ну и (30) добавляет нюанс
52 Fragster
 
гуру
31.10.18
15:42
а зачем тут первая ветка Если?
53 PR
 
31.10.18
15:48
(51) Если число не пограничное, то есть, например, не 1.5, то пофиг как округлять
54 PR
 
31.10.18
15:50
(51) В (30) не нюанс, а бред сивой кобылы какой-то, 21452,3456 с округлением до двух знаков — это не пограничное число, с какого рожна после округления должно стать 21452,34, а не 21452,35, спрашивается?
55 Fragster
 
гуру
31.10.18
15:50
(53) вот именно. по этому эту проверку можно вообще убрать и оставить только то, что в Иначе
56 PR
 
31.10.18
15:51
(55) Охренеть. И чему тогда будет равно РежимОкругленияЧисла?
57 Fragster
 
гуру
31.10.18
15:52
ну и
     ПоловинаОкругленногоЧисла = Окр(Число, Разрядность, РежимОкругления.Окр15как10) / 2;
    
    Если ПоловинаОкругленногоЧисла = Окр(ПоловинаОкругленногоЧисла, Разрядность, РежимОкругления.Окр15как10) Тогда
реально эквивалентно
ЧислоДляРежимаОкругления % 2 < 1
только у меня короче
58 Fragster
 
гуру
31.10.18
15:52
(56)
    Если ПоловинаОкругленногоЧисла = Окр(ПоловинаОкругленногоЧисла, Разрядность, РежимОкругления.Окр15как10) Тогда
        РежимОкругленияЧисла = РежимОкругления.Окр15как10;
    Иначе
        РежимОкругленияЧисла = РежимОкругления.Окр15как20;
    КонецЕсли;
59 Fragster
 
гуру
31.10.18
15:52
чему-то да будет равно, но поскольку пофиг - то пофиг
60 PR
 
31.10.18
15:56
(57) Никогда не любил укорачивателей, читай сишников
Напишут строчку в 60 символов, в которой расчет суммы документа зашифрован, никуя непонятно, хрен уже что исправишь, чтобы разобраться в смысле, надо месяц расшифровывать в человеческий вид, зато автор ходит гоголем, аж рубашка на груди трещит
61 Fragster
 
гуру
31.10.18
15:57
(60) ну если для тебя функция остатка от деления сложна, то пора начинать думать о карьере менеджера, а не программиста
62 PR
 
31.10.18
15:58
(58) А, ви в етом смисле
Ну наверное да, лень думать
63 Fragster
 
гуру
31.10.18
15:58
или оператор ?(,,)
64 Fragster
 
гуру
31.10.18
15:58
(62) > лень думать
все беды от этого, и (60) тоже
65 PR
 
31.10.18
15:59
(61) Функция остатка от деления оперирует предварительно рассчитанным числом
Так-то и в C все просто, 255 символов и все, епта, но реально 60 символов можно неделю расшифровывать
66 PR
 
31.10.18
16:01
(64) Мой код читабельнее, его легче проверить и его легче отлаживать
Практически всегда эти аргументы важнее, чем экономия места на винчестере
67 Fragster
 
гуру
31.10.18
16:02
(65) ну на самом деле понять, что ты имеешь ввиду под сравниванием половины округленного числа с его же округлением сложно. а проверка на самом деле та же - что число лежит в диапазоне четное +-1
68 Fragster
 
гуру
31.10.18
16:02
(66) не уверен
69 Fragster
 
гуру
31.10.18
16:03
(10) и (36) да, повыпендриваться. а (48) уже норм, можно комментарий добавить, конечно.
70 PR
 
31.10.18
16:04
(67) Поэтому сначала я хотел написать что-то типа "ЭтоПограниченоеЧисло = ..." и "ЭтоЧетноеЧисло = ...", так и надо было сделать :))
71 PR
 
31.10.18
16:04
+(70) Пограничное конечно же
72 PR
 
31.10.18
16:11
(68) В чем не уверен?
Что чем ниже сложность кода, тем он читабельнее?
Или что чем ниже сложность кода, тем его легче проверить?
Или что чем меньше операторов в одной строке кода, тем легче отлаживать код?
73 PR
 
31.10.18
16:12
(69) С этим да, соглашусь, (48) уже терпимо, с комментариями вообще зайдет нормально
74 Fragster
 
гуру
31.10.18
16:13
(71) достаточно нарисовать условие в мат. терминах:

(2n+1 -0.5, 2n+1 + 0.5) -> 2n+1
[2n - 0.5, 2n + 0.5] -> 2n

и все становится просто. + некоторый нюанс из (30)
75 ReaLg
 
31.10.18
16:13
Я правильно понял, что 1,331 округляется до 1,34 а 1,289 до 1,28?
Тогда так можно:
Число2 = ПервоначальноеЧисло * Pow(10, Разрядность);
Число3 = Цел(Число2);
Число4 = ?(Число3 % 2 = 0, Число3, Число3 + 1);
Результат = Число4 / Pow(10, Разрядность);  

Только надо еще понять, правильно ли что 0,004 - это 0 и 1,291 это 1,3
76 Fragster
 
гуру
31.10.18
16:14
и именно вариант с остатком от деления для определения вида числа ближе (для меня :))
77 PR
 
31.10.18
16:14
(74) Добавляет сложности в понимание то, что округляется до n знаков, а не до 0 или до 2
78 Fragster
 
гуру
31.10.18
16:14
(75) неправильно
79 Tonik992
 
31.10.18
16:14
(6) В большинстве случаев - да. Я за такой код.
(8) Не могу понять, почему нарушает эффективность? Что значит эффективность по отношению местонахождения "Возврат" ?
80 Вафель
 
31.10.18
16:14
(75) вроде только цифра 5 округляется по разному
81 Fragster
 
гуру
31.10.18
16:15
(77) этим в данном случае можно пренебречь. собственно, в ОКР это добавили чисто для удобства, в ЦЕЛ - забили.
82 Fragster
 
гуру
31.10.18
16:16
(81) дать правильное определение n, не целое число, а целое, поделенное на 10 в степени разрядность
83 ReaLg
 
31.10.18
16:17
(80) В (21) написано к ближайшему четному. Про цифру 5 ничего нет. Для 2.331 ближайшее четное (во втором знаке после запятой) это 2.34 :))
84 PR
 
31.10.18
16:18
(75) Хм, что-то я по ходу неправильно свой вариант написал, надо еще раз прочитать про банковское округление

Интересно, в чем смысл округления до ближайшего целого?
85 Fragster
 
гуру
31.10.18
16:18
(83) правильно, надо у заказчиков требовать тест кейсы
86 PR
 
31.10.18
16:19
+(84) До ближайшего четного в смысле
87 ReaLg
 
31.10.18
16:20
(85) Ну я поэтому и заинтересовался - что по (21) я понял задачу не так, как ее в топике решают :))
88 Fragster
 
гуру
31.10.18
16:22
(83) до ближайшего четного в (2)
89 PR
 
31.10.18
16:30
Короче, ТС нихрена не написал, что такое сабж
http://stan-1.ru/bankovskoe-okruglenie-okazyvaetsya-est-i-takoe/
90 PR
 
31.10.18
16:38
+(89) Мда, эта статейка тоже по ходу не эталон
Нужно определение банковского округления
Исходя из здравого смысла люди хотели для сокращения накопленных округлений спорных чисел округлять их четные влево, нечетные вправо
91 PR
 
31.10.18
16:45
То есть для округления до двух знаков:
- Все числа с дробной частью "ab5", где b четное, округляются по правилу РежимОкругления.Окр15как10
- Все числа с дробной частью "ab5", где b нечетное, округляются по правилу РежимОкругления.Окр15как20
— Все остальные числа округляются как угодно (результат будет одинаковым), пусть хоть по правилу РежимОкругления.Окр15как10

Тогда я вроде как верно написал :))
92 PR
 
31.10.18
16:51
+(91) На всякий случай, числа "123.125001", "123.124999" и "123.125500" попадают в прочее
93 Вафель
 
31.10.18
16:52
так вроде для округления до 2х знаков
123.125001 == 123.125
94 PR
 
31.10.18
16:57
(93) 123.125001 не является спорным, оно без вариантов округляется вверх до 123.13
95 bolobol
 
31.10.18
16:59
(94) И, конечно же - 3 - это самое чётное из всех
96 Вафель
 
31.10.18
17:00
(94) Эх Рома-Рома, такую простую задачу не осилил
97 PR
 
31.10.18
17:03
+(94) Спорным для округления до двух знаков является число, где округляемый остаток равен ровно 0.005, когда непонятно, то ли вторую цифру после запятой увеличивать на 1 то ли нет
То есть в 123.125001 округляемый остаток равен 0.005001, а это больше, чем 0.005, значит нужно увеличивать, получится 123.13
98 PR
 
31.10.18
17:03
(95) Рукалицо
Напиши определение банковского округления
99 PR
 
31.10.18
17:04
(96) Смехуёчки в строю
100 bolobol
 
31.10.18
17:08
(98) Повторить, штолле? Самому не осилить вики и в 100 постах не найти цитату определения?
101 PR
 
31.10.18
17:23
(100) Ну повтори, если видишь _определение_, а я не вижу
Или не выеживайся
Закон Брукера: Даже маленькая практика стоит большой теории.