гофи2
Последно редактирано на 04.12.2020 от гофи2, видяно: 3507 пъти. #20425
Дойде ми време да се възползвам, че попаднах във форум дето има математици.
Проблема ми е следния. Дадена ми е една ел. таблица и трябва да въвеждам IBAN в нея. Е да де, ама аз не съм сигурен в себе си и искам да съм сигурен, че съм ги въвел правилно. Това да проверя, че е 22 знака и има верен БАЕ не ме успокоява. Искам да съм сигурен.
Според Наредба 13 на БНБ (писана по европейски стандарт) IBAN се преобразува в число, след което се взима неговия модул 97. Всичко това е прекрасно, докато се оказа, че електронната таблица (АОО в моя случай) не умее да борави (смята) с големи числа.
Преди седем години, когато правих подобно нещо на Perl, просто заредих приставка за BigInt и заспа. Но тук нямам такава екстра.
Та въпроса е, има ли начин тази сметка някак си да се разбие на повече стъпки с по-малки числа, така, че в крайна сметка да се получи точна сметка?
Би трябвало да може да се направи. Преди да има компютри, хората са ги смятали тия неща на ръка. Значи не може да не са измислили някакъв алгоритъм за по-лесни сметки.
Modulo operation on IBAN
Any computer programming language or software package that is used to compute D mod 97 directly must have the ability to handle integers of more than 30 digits. In practice, this can only be done by software that either supports arbitrary-precision arithmetic or that can handle 220 bit (unsigned) integers,[Note 2] features that are often not standard. If the application software in use does not provide the ability to handle integers of this size, the modulo operation can be performed in a piece-wise manner (as is the case with the UN CEFACT TBG5 Javascript program).
Piece-wise calculation D mod 97 can be done in many ways. One such way is as follows:[14]
Starting from the leftmost digit of D, construct a number using the first 9 digits and call it N.[Note 3]
Calculate N mod 97.
Construct a new 9-digit N by concatenating above result (step 2) with the next 7 digits of D. If there are fewer than 7 digits remaining in D but at least one, then construct a new N, which will have less than 9 digits, from the above result (step 2) followed by the remaining digits of D
Repeat steps 2–3 until all the digits of D have been processed
The result of the final calculation in step 2 will be D mod 97 = N mod 97.
Example
In this example, the above algorithm for D mod 97 will be applied to D = 3214282912345698765432161182. (The digits are colour-coded to aid the description below.) If the result is one, the IBAN corresponding to D passes the check digit test.
Construct N from the first 9 digits of D
N = 321428291
Calculate N mod 97 = 70
Construct a new 9-digit N from the above result (step 2) followed by the next 7 digits of D.
N = 702345698
Calculate N mod 97 = 29
Construct a new 9-digit N from the above result (step 4) followed by the next 7 digits of D.
N = 297654321
Calculate N mod 97 = 24
Construct a new N from the above result (step 6) followed by the remaining 5 digits of D.
N = 2461182
Calculate N mod 97 = 1
From step 8, the final result is D mod 97 = 1 and the IBAN has passed this check digit test.
Нека вземем за пример IBAN BG80BNBG96611020345678;
Слагаш първите 4 отзад, за да стане BNBG96611020345678BG80
После минаваш през всеки ascii char и вземаш неговата стойност от ascii таблицата;
ако е letter (not a number), изваждаш 55
получаваш 1123111696611020345678111680
в един акумулатор, наречи го чексума, присвояваш първата стойност (на позиция 0), т.е., 1.
В цикъл въртиш от позиция 1 на 1123111696611020345678111680 до края на стойността
чексума *= 10
чексума + числото на текущата позиция
чексума %= 97
накрая чексума трябва да ти е == 1
На netcore ще изглежда така:
class Program
{
static void Main(string[] args)
{
string input = "BG80BNBG96611020345678";
string rearranged = input.Substring(4, input.Length - 4) + input.Substring(0, 4);
StringBuilder sb = new StringBuilder();
foreach (var @char in rearranged)
{
int temp;
if (char.IsLetter(@char))
temp = @char - 55;
else
temp = int.Parse(@char.ToString());
sb.Append(temp);
}
string asciiCoded = sb.ToString();
int checksum = int.Parse(asciiCoded.Substring(0, 1));
for (var i = 1; i < asciiCoded.Length; i++)
{
checksum *= 10;
checksum += int.Parse(asciiCoded.Substring(i, 1));
checksum %= 97;
}
Console.WriteLine(checksum == 1);
}
}
Ако ти трябва за ексел, преведи си онлайн c#-а на vb и го сложи в macros в ексела.
fn main() {
let num = "3214282912345698765432161182";
let mut result = 0u64;
for &b in num.as_bytes() {
let c = b as u64 - '0' as u64;
result = (result * 10 + c as u64) % 97;
}
println!("Result: {}", result);
}
гофи2
Създадено на 04.12.2020, видяно: 3469 пъти. #20459
Благодаря Фейк! Ще се опитам да го разгадая.
Благодаря и на Courvoisier, но за съжаление директното ползване на mod(ulo) или каквито и да е действия върху големи числа не работят. Точно затова искам да разбия на по-малки.
Няма да минеш 32767, макар понякога да минаваш 255. Мисля, че и Фейка на ръст ти ги смята в unsigned 64 bit, макар да се побира в по- малко. Мисля, че в най- лошия случаи ще ти остане 96, което ще умношиж по 10 и после да добавиш 9, което ще е 969. Трябва ти арей от char-ове и 16-bit numeric.
Какво е AOO?
ДонРеба
Създадено на 04.12.2020, видяно: 3465 пъти. #20461
в неговия метод чексумата е малко число. не мога с един поглед да кажа дали бачка, по математика бях на четворки, но може и да бачка
гофи2
Създадено на 04.12.2020, видяно: 3461 пъти. #20462
Ами в ел. таблици няма конкретно int (прави вътрешни преобразувания за оптимизация), както би било в Ц. И явно сваля все пак осем байта, щом прави проблем. Проверих в Интернет и буквално закръгля до най-близкото цяло число. А на мен ми трябва остатъка. Кофти тръпка.
гофи2
Създадено на 04.12.2020, видяно: 3459 пъти. #20463
Извинявам се! Понякога не се усещам, че не говоря със себеподобни.
гофи2
Последно редактирано на 04.12.2020 от гофи2, видяно: 3453 пъти. #20465
Сега го забелязах, но, колкото и да препрочитам, не успявам да разбера, на какво казва контролен сбор. Ц Диез не е точно моето, ъ-ъ-ъ. Казах ли, че съм ламер?
Това за ascii е гениано и ми спестява много. В наредбата е дадено като таблица, без да се казва, как е определена.
доп.
===
Даже не стигам до числото му. Според мен трябва да е 9661102034567811168011231116, а не 1123111696611020345678111680.
Хммм... като правиш integer % 97 ти прави грешка? Я дай скрипта, пише, че е доста подобен на VB.
От друга страна, в гугъл шийт макросите се пишат с javascript и си имаш API. Може би най- интелигентното решение, ако не ти пука, че гугъл ти виждат данните.
Като сложиш първите 4 отзад, става BNBG96611020345678BG80. Обърни внимание, че IBAN е с ГЛАВНИ БУКВИ. Главните букви са ASCII - 55. Числата си остават числа. Трябва да получиш голямо число, което може да е стринг (или арей от char), като всяка буква е нейния ASCII Код - 55, а числото се запазва.
Ако погледнеш кой символ какво е в ASCII (http://www.asciitable.com/) ще получиш:
B = 66 - 55; защо изваждаш 55 не мога да ти кажа, но алгоритъмът е такъв = 11
G = 78 - 55 = 23
B = 66 - 55 = 11
G = 71 - 55 = 16
9 = 9
6 = 7
6 = 6
1 = 1
1 = 1
0 = 0
2 = 2
0 = 0
3 = 3
4 = 4
5 = 5
6 = 6
7 = 7
8 = 8
B = 66 - 55 = 11
G = 71 - 55 = 16
8 = 8
0 = 0
Така получаваш 11 23 11 16 9 7 6 1 1 0 2 0 3 4 5 6 7 8 11 16 8 0. Но ще го обработваш цифра по цифра, а не число по число.
После, акумулаторът ти си присвоява цифрата на позиция 0 = 1
после в цикъл въртиш останалите от позиция 1 до позиция броя на цифри. Т.е., започваш от Index=1
1[1]23111697611020345678111680
1 * 10 = 10
10 + 1 = 11
11 % 97 = 11
11[2]3111697611020345678111680
11 * 10 = 110
110 + 2 = 112
112 % 97 = 15
112[3]111697611020345678111680
15 * 10 = 150
150 + 3 = 153
153 % 97 = 56
1123[1]11697611020345678111680
56 * 10 = 560
560 + 1 = 561
561 % 97 = 76
.... (прескачаме малко итерации) ...
112311169761102034567811168[0]
68 * 10 = 680
680 + 0 = 680
680 % 97 = 1
Крайният резултат е 1. За да е валиден IBAN трябва да е 1.
Worst case, ще имаш 96 (96 % 97 = 96) от предната итерация, която ще се умножи по 10 и ще се прибави 9, но после ще го намалиш, защото ще направил модуло 97.
code2
Създадено на 04.12.2020, видяно: 3439 пъти. #20472
Не съм гледал какви кодове са ти дали, но си спомням още от училище, че се учеха така наречените признаци за делимост на 3 и на 11. Всъщност точно такъв механизъм се ползва за да се вземе нужния остатък. Помня също, че имаше някакъв признак за делимост на 19, но той беше съвсем друга бира (че да не беше и твърд алкохол...).
За 3, сбора на цифрите също се дели на 3. Например 15 => 1 + 5 = 6 % 3 = 0. Но това как ти помага за модулo 97?
code2
Създадено на 04.12.2020, видяно: 3435 пъти. #20475
За 3, сбора на цифрите също се дели на 3. Например 15 => 1 + 5 = 6 % 3 = 0. Но това как ти помага за модулус 97?
В доказателството на споменатото "За 3, сбора на цифрите също се дели на 3." се използва взимане по модул 3 на числата 10^n, които точно в този случай са само единици. В този ред на мисли при 97 ще имаме число, което със сигурност е по-малко от 10*22*97=21340. А ако изчисляваш на всяка стъпка по модул няма да имаш числа по-големи от 11*97, независимост от дължината на числото.
Естествено горе споменатото не е толкова елегантно като очевидната техника за бързо умножение на полином, но пък е нещо сравнително познато.
ДонРеба
Създадено на 05.12.2020, видяно: 3394 пъти. #20499
в неговия метод чексумата е малко число. не мога с един поглед да кажа дали бачка, по математика бях на четворки, но може и да бачка
Сега го забелязах, но, колкото и да препрочитам, не успявам да разбера, на какво казва контролен сбор.
ами на това което в крайна сметка ще ти даде резултата от модул по 97
механизма на решението е "акумулатор с превъртане", нещо като циферблат на часовник. стрелката показва 5, добавяш и 3 "часа", показва 8. добавяш още 7 "часа" и вече показва 3 (15 мод 12). горното решение е същото, само че часовника ти има 97 "часа", а не 12. всяко поредно събираемо е малко, затова нямаш грижи. може би не е много нагледно за който не е виждал часовник със стрелки, ама по-нагледно не се сещам :)
Delegate
Създадено на 05.12.2020, видяно: 3389 пъти. #20501
Може и да не са виждали часовник с "ръце" , ама тука всички разбират от Diffie Hellman и съм сигурен, че са втрещявали момичетата в класа, като са познавали за секунди кой ден от седмицата е някаква случайна дата.
гофи2
Създадено на 05.12.2020, видяно: 3380 пъти. #20503
БЛАГОДАРЯ на всички, които се включиха в темата и дадоха от времето си. Най-много благодаря на Курвазие и Дон Реба, които обясниха алгоритъма точно като за полуидиот, какъвто за жалост или за радост съм.
Чудесни сте!
п.п. Разликата между голямото число на Курвазие и моето беше, понеже съм цял идиот и бях взел неговия IBAN, когато вече беше преместил последните четири знака отзад. Ама това го видях едва днес на сутрешното кафе. Снощи трябваше да готвя за домашните, след което слушах спортното шоу на „Дарик“, напих се лошо с ракия и дори не успях да гледам Сашо Диков.