Pull to refresh
4
Send message

Компилятор не может здесь ничего "оптимизировать" (как минимум без flto), в случае с копированием вектора (без std::move), вы обязаны создать копию, а вектор-аргумент останется не-пустым (и естественно должен указывать на другую память, иначе при вызове деструкторов случился бы "double-free"), в случае с std::move вы перекидываете указатели на уже выделенную память, а вектор аргумент содержит nullptr-ы. Если например тестирующая обертка логгирует size у тестового вектора после вызова нашей функции - то и flto никак не поможет.

Я бы сказал это архетипичный пример мув-семантики, недоступный до её введения в стандарт. До С++11 приходилось делать так:

    vector<int> replaceNonCoprimes(vector<int>& nums) {
        vector<int> ans;
        ans.swap(nums);
        ...
        return ans;
    }

Работает полностью аналогично, и тут как раз срабатывает корректная оптимизация NRVO (обязательная с C++17), и кстати с таким подходом std::move будет только всё портить.

Строчка с nums.erase только отвлекает, она тут не причём. Главное что мы не просто используем входную память для своих вычислений, а то что мы не выделяем никакую другую.

Ну и если нам разрешают менять аргумент функции, значит и разрешают сделать его пустым, украв его память. И естественно что выкинув из решения аллокацию на полмегабайта оно станет быстрее.

Вместо того что бы выделять новый вектор под ответ, можно отдать уже выделенную память, раз уж нам разрешили менять аргумент.

vector<int> replaceNonCoprimes(vector<int>& nums) {
  ...
  nums.erase(nums.begin() + k, nums.end());
  return std::move(nums);
}

Memory: Beats 99.62%

About

A simple MP3 editing tool for Windows. Not open source.

настоящей проверки качества прогнозирования

В ML выборку принято делить на Training, validation, and test как раз что бы избежать переобучения во время подбора модели/гиперпараметров, это база.

Буквально первый комментарий на скриншоте про "putting kernel level anti-cheat". Ну и на сайте Denuvo честно признаются чем они (с позиции критики конкурентов) там занимаются:

(3) Anti-cheat 1, 2 and 3 access all files on your disk that are opened while the anti-cheat is running by using a file system minifilter, a formal operating system hook. This minifilter passes all opened files to the anti-cheat software, not just those that interact with the game.

 Anti-cheat 3 uses Windows’ Early Launch AntiMalware (ELAM) security feature which allows the kernel-mode driver to start before all others. This behavior is often mistakenly referred to as a rootkit, which it is not because it does not attempt to hide from the user and is effortless to remove.

Никаких проблем подключиться к процессу и читать его память нет, `Cheat Engine/Artmoney` 100 лет в обед, и никаких "особенных" привилегий для их работы не нужно.

Школьное "подгоняем под ответ" вышло на новый нейросетевой уровень.

Надеюсь вы знаете что такое train validation test split, а то мне страшно за АЭС.

У меня получилось сжать переведённую "Войну и Мир" обычным RLE вне зависимости от числа повторений, попробуйте Энтропийное кодирование для потока битовых флагов.

p=2.45%
theoretical limit=66453.89161197383
rANS= 66477
rANS inefficiency=0.03%
origin=3202320
result=3190338
factor=0.37%

Вот код. Вроде бы и немного (21+18 строк), но он довольно таки ёмок на математику, легко допустить ошибку. Если будет несложно дополните статью, так она станет гораздо информативнее.

Максимально дубовая реализация монтгомери вместе с делением по Лемиру улучшила мой результат с 27,223 до 21,820 . Даже обидно как-то, получается раньше я вообще не в ту сторону смотрел. Но теперь до первых мест рукой подать, скорее всего можно те же вызовы _mullo_epi32 в два раза реже делать (у меня на 1 mulmod 3 simd умножения, из которых только два полноценное, и одно урезанное), или от бранча для переполнения вычитания как-то отказаться, его обработка съедает четверть всего времени. Теоретически можно оптимально распланировать умножения по битам степени, и вместо маскировки делать их только тогда когда нужно, это тоже может дать до трети всего времени (умножаем только на половину всех битов).

Да, проверяю по 4 числа одновременно. Главное заранее отсекать большую часть работы (5/6) проверкой на делимость на маленькие делители, довольно красиво сделано, но видимо можно сделать лучше, я использовал для больших libdivide_u32_do_vec256, а для маленьких (2,3,5,7) сообразил трюк с _mm256_shuffle_epi8. Тоже в восторге от результатов первой тройки. Ах да, еще нужно чтение через mmap организовать, в справке от сайта есть пример.

О, я примерно тем же путём шел когда решал https://highload.fun/tasks/10

Правда у меня в итоге векторизованная где-то в 2 раза быстрее не векторизованной, но и другие трюки использовал. Обязательно поделитесь результатом.

а с чего это вы взяли

Все так говорят (на один символ отправка 8 байт если между ними меньше ~20ms), пробежал по коду и не вижу ничего противоречащего этому. Тестить правда лень, если хотите оспорить — wireshark/tcpdump вам в помощь.

подмешивается немного мусора

Действительно в прошлом году появился патч и опция в конфиге, мне интересно, а в вашем дистрибутиве есть эта опция? (проще всего проверить man ssh_config; /Obf)

Презентация про ssh, тут статья. Текст об этом на хабре, но я не рекомендую ни комментарии ни статью: там какая-то отсебятина про visual feedback.

Но в таком случае происходит утечка данных не только о тайминге нажатий, но и о количестве клавиш, что соответствует длине пароля

Вместе с таймингом утекает и длина пароля, ответных пакетов со стороны сервера не нужно.

В комментариях тоже какая-то дичь, например: (проблема не в комментарии или в комментаторе, а в том что его никто не поправил, так и висит).

в SSH автоматически включается Nagel's и передаваемые символы начинают группироваться и объединяться, что портит хакерам весь праздник

/* Informs that the current session is interactive.  Sets IP flags for that. */

void
ssh_packet_set_interactive(struct ssh *ssh, int interactive, int qos_interactive, int qos_bulk)
{
    ...
	set_nodelay(state->connection_in);
    ...
}

/* disable nagle on socket */
void
set_nodelay(int fd)
{
    ...
    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
		error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
}

Статья про анализ серверного "пинга" со стороны собеседника в IM.

Напишу на тот случай если кто-то не понимает какую конкретно безопасность обеспечивает ‎E2EE и для/от кого. Для любого мессенджера с моментальной доставкой сообщений и без серьёзного "замусоривания" траффика легко понять кто с кем общается используя глобальное наблюдение (без MitM) и элементарные корреляции.

Пусть пользователь A, B живут в стране, где некие вредоносные агенты Е установили специальное оборудование сохраняющее метаданные всего оконечного трафика на всех провайдерах связи. Пусть агенты E знают A, но не знают B, про B известно что он один из множества U.

Теперь каждый раз когда A пишет сообщение B, он инициирует обмен сетевым трафиком с серверами напрямую (Telegram), через peer-to-peer сеть(Tor), либо даже с использованием туннеля с дополнительным шифрованием ( Wireguard или OpenVPN). Но во всех популярных любительских сценариях использования (за редким исключением вроде i2p) размеры пакетов меняются крайне предсказуемо, а то и не меняются вовсе. Теперь E, зная паттерны трафика нового сообщения (а в случае push уведомлений можно опираться и на ip-подсеть как на показатель пуша), запоминает текущее время.

Затем это сообщение должно прийти B, где ситуации повторится. Так как множество людей из U могут получить подобный трафик случайно, E может лишь ограничить размер множества U - даже для довольно таки большого окна доставки в минуты (типично для пуш-уведомлений) с каждым сообщением размер U будет сокращаться в разы, если не в десятки. Для однозначного установления B потребуется около 27 бит информации (|U|~=1.4e8), что вполне себе достижимо при регулярном общении. Даже если утекать будут малые доли бита (т.е. агенты E очень не уверены в том что произошло общение), из того что нам их нужно собрать буквально десятки, при достаточном количестве сообщений легко вычислить весь граф общения.

Эту картину не меняет даже вменяемый false-positive (пусть например фоном запущенный ютуб раз в 15 секунд даёт картину похожую на сообщение, тогда мы должны учесть шанс того что A ничего не отправлял). В таком случае мы не выкидываем кандидатов из U, а честно обновляем ожидания по Байесу. Если проделать подобное в итоге получатся что граф общения оказывается (ребро между вершинами если они общаются) равен попарной временной корреляции "интересного" трафика относительно U.

Подправив параметры можно узнать например на какие каналы в youtube вы подписаны не залезая в шифрованный трафик, достаточно посмотреть корреляцию жирного потока на сервера гугла с расписанием публикации новых видео, (если вы конечно открываете их сразу по уведомлению).

Да, это вычислительно сложная задача, но явно не сложнее подсчета условного PageRank-a для поискового индекса с MapReduce, естественно считать в лоб (O(|U|^2)) нельзя.

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

Определение местоположения пользователя популярных "защищенных" мессенджеров

Тут исследователи не пользуются глобальным мониторингом траффика, смотрят только на раундтрипы оповещения о доставке.

P.S.
Задумался над тем что бы комментарий до статьи добить, но об подобном на хабре уже писали еще в 2011 (в контексте Tor, Tarzan и Morphmix).

Еще я сомнительным способом генерировал случайное целое, uniform_uint64() % (HI-LO) + LO В районе 10^18 там уже значительный перекос в пользу меньших чисел.

Было бы любопытно узнать, как график ведёт себя на бесконечности

Прогнал Монте-Карло на равномерных неупорядоченных парах, (это не точно учтёт пары где x=y, но так как их немного, погрешность должна быть небольшой).

Просто взял p:=cnt_good/cnt_iters; estimate:=81*10^{d-2}*p/2;

Скорость симуляции получилась около 5 миллиардов итераций в секунду, что не впечатляет. Пришлось немного попотеть что бы правильно работать с 36-значными числами.

Monte-Carlo
# [x y]
# d=d elapsed_time p_good estimate_pairs
# [269 581]
# d=3 129.385 3.851820e-04 1.559987e+02
# [4395 8691]
# d=4 154.701 8.392064e-05 3.398786e+03
# [87365 79139]
# d=5 155.051 2.766043e-05 1.120248e+05
# [775100 162389]
# d=6 154.746 1.113085e-05 4.507995e+06
# [2530020 4761510]
# d=7 207.304 5.262449e-06 2.131292e+08
# [85693413 36003975]
# d=8 233.018 2.778503e-06 1.125294e+10
# [345731723 932322371]
# d=9 234.242 1.595132e-06 6.460286e+11
# [8388016499 5721446594]
# d=10 237.009 9.736462e-07 3.943267e+13
# [40264350366 98521508913]
# d=11 237.098 6.248657e-07 2.530706e+15
# [919177426937 734068423163]
# d=12 237.305 4.179230e-07 1.692588e+17
# [8616586083842 7797719745830]
# d=13 267.747 2.884882e-07 1.168377e+19
# [45126923716086 53984469270216]
# d=14 270.713 2.058496e-07 8.336909e+20
# [204357829294211 514926408573260]
# d=15 269.294 1.502094e-07 6.083479e+22
# [6896406641595237 8139155118610023]
# d=16 319.639 1.116254e-07 4.520827e+24
# [62459283066899325 52619943312077259]
# d=17 343.897 8.466919e-08 3.429102e+26
# [409783614423487398 781679240519529663]
# d=18 344.870 6.535767e-08 2.646985e+28

Относительная точность падает при уменьшении p, поэтому оценку для d=18 получилось посчитать с точностью ±0.3%

Monte-Carlo
Monte-Carlo

Hidden text
@cuda.jit
def cuda_pairs_core(A, B, C, C1, C2, d, base):
    # ...
    if p_i + 1 < A.size and p_j + 1 < A.size:
        i0, i1 = A[p_i], A[p_i + 1]
        j0, j1 = A[p_j], A[p_j + 1]
        cnt = uint64(0)
        for i in range(i0, i1):
            k = uint64(i * max(j0, i))
            k_hi = uint64(k // b_lim)
            k_lo = uint64(k % b_lim)
            for j in range(max(j0, i), j1):
                if k >= low_lim:
                    if C[k_hi] + C1[k_lo // c2_lim] + C2[k_lo % c2_lim] == C[i] + C[j]:
                        cnt += uint64(1)
                k += i
                k_lo += i
                if k_lo >= b_lim:
                    k_lo -= b_lim
                    k_hi += uint64(1)
        cuda.atomic.add(B, (t_i, t_j), cnt)

@njit
def init_c(C, d, BASE):
    p = 1
    for i in range(d):
        for j in range(p - 1, -1, -1):
            for z in range(BASE - 1, -1, -1):
                C[j * BASE + z] = C[j] + (uint64(1) << (z * 4))
        p *= BASE

Попробовал ваш алгоритм на видяшке, работает 4.5 секунды для n=6.

Заодно и осилил n=7

7
2 -> 0.871
156
3 -> 0.002
3399
4 -> 0.002
112025
5 -> 0.018
4505706
6 -> 4.435
213002162
7 -> 974.439

Переписав на С++, на вычисление ушло 25 минут

Лобовой подсчет без каких-либо алгоритмов на видяшке работает 4 секунды! (задача с парами). Если не лень ждать 16 часов сможете узнать ответ для n=7.

7
2 -> 0.675
156
3 -> 0.001
3399
4 -> 0.044
112025
5 -> 4.365
4505706
6 -> 537.973
Hidden text
@cuda.jit(device=True)
def cuda_pair_check(i, j, k, d, base):
    a = cuda.local.array(base, np.uint8)
    for z in range(base):
        a[z] = 0
    for z in range(d):
        a[int(i % base)] += 1
        i = i // base
        a[int(j % base)] += 1
        j = j // base
    for z in range(2*d):
        a[int(k % base)] -= 1
        k = k // base
    nz = 0
    for z in range(base):
        if a[z] == 0:
            nz += 1
    return nz == base


@cuda.jit
def cuda_pairs_core(A, B, d, base):
    assert base == 10
    p_i, p_j = cuda.grid(2)
    t_i, t_j = cuda.threadIdx.x, cuda.threadIdx.y
    low_lim = 1
    for k in range(2*d - 1):
        low_lim *= base
    if p_i + 1 < A.size and p_j + 1 < A.size:
        i0, i1 = A[p_i], A[p_i + 1]
        j0, j1 = A[p_j], A[p_j + 1]
        cnt = uint64(0)
        for i in range(i0, i1):
            i = uint64(i)
            for j in range(j0, j1):
                j = uint64(j)
                if i <= j:
                    k = uint64(i * j)
                    if k < low_lim: continue
                    if cuda_pair_check(i, j, k, d, 10):
                        cnt += 1
        cuda.atomic.add(B, (t_i, t_j), cnt)

def run_cuda_pairs(d):
    num = 2**10
    A = np.linspace(pow(BASE, d - 1), pow(BASE, d), num).astype(np.uint64)
    threads = (2**5, 2**4)
    B = np.zeros(threads, dtype=np.int32)
    blocks = (
            (A.size - 1 + (threads[0] - 1)) // threads[0],
            (A.size - 1 + (threads[1] - 1)) // threads[1],
    )
    A, B = cuda.to_device(A), cuda.to_device(B)
    cuda_pairs_core[blocks, threads](A, B, d, BASE)
    B = B.copy_to_host()
    return np.sum(B)

def main_pairs():
    print(f'start {datetime.datetime.now()}')
    for d in range(2, 8):
        t0 = time.perf_counter()
        cnt = run_cuda_pairs(d)
        t1 = time.perf_counter()
        print(cnt)
        print(f'{d} -> {t1-t0:.3f}')

Ничего не нашлось, а пятнадцать нужно 16 часов ждать. Расширил пространство на несколько порядков, вдруг пригодится потомкам.

Другие основания, из не указанного выше
M=2
(40) 1100111001101110111101000000000100000011 * 1010110100001000010111011110000111010001 = 1000101110000111101110100001000010110101 1100000010000000001011110111011001110011
(42) 111010101010110001000001000101111001101011 * 101100101100110011100110011110011111000101 = 101000111110011110011001110011001101001101 110101100111101000100000100011010101010111

M=3
(18-26) None

M=4
(11) 20221122201 * 33313301202 = 20210331333 10222112202
(12) 220032112122 * 220231112121 = 121211132022 221211230022
(13) 3033122211023 * 2021000003321 = 1233000001202 3201122213303
(19) 3123010113323033123 * 1223000330230123211 = 1123210320330003221 3213303233110103213
(20) 21123300031031323121 * 33203011213013222012 = 21022231031211030233 12132313013000332112
(21) 231122200023011022212 * 200211130021013310311 = 113013310120031112002 212220110320002221132
(21) 131012330133313121331 * 220013120002032330201 = 102033230200021310022 133121313331033210131

M=5
(10) 4402131124 * 1403420431 = 1340243041 4211312044
(10) 4424311302 * 2243042322 = 2232403422 2031134244
(13) 1322024130211 * 4242031404321 = 1234041302424 1120314202231
(15) 204304333140412 * 314110410304121 = 121403014011413 214041333403402
(16-18) None

M=6
(10) 2344420112 * 2433414111 = 1114143342 2110244432
(10) 2230332102 * 3120354411 = 1144530213 2012330322
(10) 1440535111 * 5043054031 = 1304503405 1115350441
(14) 21240011132212 * 42005450351431 = 13415305450024 21223111004212

M=7
(13) 5054030524163 * 5540446553414 = 4143556440455 3614250304505
(14) 26623462035461 * 52046210055512 = 21555001264025 16453026432662

M=8
(10) 6774770256 * 1540253631 = 1363520451 6520774776
(10) 6003775002 * 4000002003 = 3002000004 2005773006
(10) 5470206021 * 7431456225 = 5226541347 1206020745
(13) 6000377750002 * 4000000020003 = 3000200000004 2000577730006

M=9
(7-13) None

M=10
(11-14) None

M=11
(12) 534338726a98 * 598050086292 = 292680050895 89a627833435

M=12
(11) a0a40435495 * 3067a602862 = 268206a7603 59453404a0a
(11) 96124b45043 * 4a8b05766a3 = 3a66750b8a4 34054b42169

M=13
(11) 628ba56c626 * 22a0bc87901 = 10978cb0a22 626c65ab826

M=14
(8-11) None

M=15
(10) 59bcc30787 * e5a4923465 = 5643294a5e 78703ccb95

M=16
(3) 269 * e12 = 21e 962
(6) ab5af2 * 848b85 = 58b848 2fa5ba
(9) 6ebade3a2 * 82b559883 = 388955b28 2a3edabe6

M=17
(2) 6a * c4 = 4c a6
(5) 473d7 * ceg53 = 35gec 7d374
(8) 88b918f2 * 8g554484 = 484455g8 2f819b88
(9) gad3cc3g9 * f8701ac2f = f2ca1078f 9g3cc3dag
(10) None

M=18
(2) 4b * a2 = 2a b4
(5) c060c * 19001 = 10091 c060c
(9) ahb305ahe * 35c8a6702 = 2076a8c53 eha503bha
(9) ad95ea864 * c531fe167 = 761ef135c 468ae59da
(9) a3h94a05h * eh2g90f88 = 88f09g2he h50a49h3a

M=19
(2) 62 * b3 = 3b 26
(3-10) None

M=20
(3) ac5 * j2a = a2j 5ca
(4) ce24 * 4j23 = 32j4 42ec
(5) g040g * 15001 = 10051 g040g
(8) 44ch32i2 * ac2jgh42 = 24hgj2ca 2i23hc44
(9) 4f55610hc * 8bb1h2h02 = 20h2h1bb8 ch01655f4

M=21
(3) 7g7 * ce4 = 4ec 7g7
(7) h41830j * 306fh92 = 29hf603 j03814h

M=22
(6) g5ldhf * 5d5334 = 4335d5 fhdl5g

M=23
(2-8) None

M=24
(5) i060i * 18001 = 10081 i060i
(5) g080g * 1c001 = 100c1 g080g
(5) m823h * ff4de = ed4ff h328m
(5) l7ch3 * h305f = f503h 3hc7l
(5) 6in21 * m4h66 = 66h4m 12ni6
(7) 68kcfj3 * 9jbkbe2 = 2ebkbj9 3jfck86
(8) 62c9lnci * c6f1gm23 = 32mg1f6c icnl9c26
(9) None

@cuda.jit
def cuda_run_core(A, oA, oB, B):
    B0 = B // BASE
    pos = cuda.grid(1)
    if pos + 1 < A.size:
        b_lo = A[pos]
        b_hi = A[pos + 1]
        for b in range(b_lo, b_hi):
            if b % BASE == 0:
                continue
            rb = rev(b)
            a0 = uint64(math.ceil(rb * 1.0 * B / b))
            for a in range(a0, a0 + BASE):
                if not (B0 <= a < B):
                    continue
                ra = rev(a)
                err = uint64(a * b - rb * B)
                if err == ra:
                    oA[pos] = a
                    oB[pos] = b
                if err > B:
                    break

Проверяет все до m=12 за минуту на видюшке. Посмотрим что будет с m=14 через пару часов.

Hidden text
@cuda.jit(device=True)
def cuda_rev(x):
    r = uint64(0)
    while x > 0:
        r = r * BASE + x % BASE
        x = x // BASE
    return uint64(r)


def run_cuda(d):
    # 10 -> 0.638
    # 11 -> 6.601
    # 12 -> 68.787
    # 13 -> 775.907
    num = 2**18
    A = np.linspace(pow(BASE, d - 1), pow(BASE, d), num).astype(np.uint64)
    oA, oB = np.zeros_like(A), np.zeros_like(A)
    threadsperblock = 2**9
    blockspergrid = (A.size - 1 + (threadsperblock - 1)) // threadsperblock
    A, oA, oB = cuda.to_device(A), cuda.to_device(oA), cuda.to_device(oB)
    cuda_run_core[blockspergrid, threadsperblock](A, oA, oB, uint64(pow(BASE, d)))
    A, oA, oB = A.copy_to_host(), oA.copy_to_host(), oB.copy_to_host()
    for x, y in zip(oA, oB):
        if x:
            print(x, '*', y, '=', rev(y), rev(x))


def main():
    for d in range(8, 16):
        t0 = time.perf_counter()
        run_cuda(d)
        t1 = time.perf_counter()
        print(f'{d} -> {t1-t0:.3f}')

1
23 ...

Information

Rating
Does not participate
Registered
Activity