Вход | Регистрация

  1  2   
1С:Предприятие :: 1С:Предприятие 8 общая

Функция Банковское округление

Функция Банковское округление
Я
   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
а если там не запятая, а десятичная точка?
функция - говно
   Fragster
 
2 - 31.10.18 - 14:30
Функция ПолучитьБанковскоеОкругление(Число, Разрядность)Экспорт
    Возврат Окр(Число/2,Разрядность)*2
КонецФункции
   Fragster
 
3 - 31.10.18 - 14:31
воспользовался википедией:
Банковское округление (англ. banker's rounding) — округление для этого случая происходит к ближайшему чётному, то есть 2,5 → 2; 3,5 → 4.
   1Сергей
 
4 - 31.10.18 - 14:31
//Если КодСимвола(СледСивол) <= 53 Тогда

Если СледСивол <= "5" Тогда
   Fragster
 
5 - 31.10.18 - 14:32
а, понял
   Hans
 
6 - 31.10.18 - 14:33
По тру кодингу "Возврат" должен быть только в конце?
   alex44ru
 
7 - 31.10.18 - 14:36
(2) блин а чего так можно что ли было )))
вот это я путём не тем пошел 
ну да и ладно, другие не заблудятся 
спасибо Ваше решение намного оптимальнее моего
   Базис
 
8 - 31.10.18 - 14:36
(3) А я думал, что в случайный момент сумма обнуляется.

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

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

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

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

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

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

Возврат Окр(Число, Разрядность, РежимОкругленияЧисла);

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

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

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

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

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

Список тем форума
Рекламное место пустует  Рекламное место пустует
ВНИМАНИЕ! Если вы потеряли окно ввода сообщения, нажмите Ctrl-F5 или Ctrl-R или кнопку "Обновить" в браузере.
Рекламное место пустует