2009-09-18 2 views
10

У меня есть byte[] testKey = new byte[8];Increment байт []

Это, очевидно, начинается со всеми байтами как 0. Я хочу, чтобы пройти через все байты и приращения по 1 на каждой итерации цикла, так в конце концов, я прохожу все возможности массива байтов. Я также хочу сделать это как можно быстрее. Да, я пытаюсь написать грубый форкер.

Обновление У меня есть небезопасный метод работы, и он самый быстрый. Тем не менее, по моим расчетам, для каждого цикла с использованием .Net DESCryptoServiceProvider потребуется 76 000 000 лет, чтобы выполнить шифрование DES. 10 000 шифров занимают 1,3 секунды. Спасибо за все потрясающие ответы на самый бесполезный вопрос!

+6

Для проверки всех комбинаций 2^64 потребуется очень много времени. –

+0

Пройдет около семи лет, чтобы перебрать все комбинации, значительно больше, если вы действительно что-то делаете с каждой комбинацией. Грубая сила, похоже, не подходит для этого ... – Guffa

+0

Да, если у вас нет вычислительных ресурсов правительственного агентства или огромной корпорации позади вас, у вас нет шансов на исчерпывающее тестирование пространства поиска размером 2^64 , Даже если для каждого теста потребовался только один цикл для работы на современном процессоре, для завершения тестирования всего пространства поиска потребовалось бы 71 тысячу лет. –

ответ

11

btw; это занимает много обработки, чтобы проверить 2^64 вариантов ...

Ну, быстрый способ может быть просто использовать Int64 (ака long) или UInt64 (ulong), а также использовать ++? Вам действительно нужен byte[]?

Как Hacky альтернативы, как насчет:

Array.Clear(data, 0, data.Length); 
while (true) 
{ 
    // use data here 
    if (++data[7] == 0) if (++data[6] == 0) 
    if (++data[5] == 0) if (++data[4] == 0) 
     if (++data[3] == 0) if (++data[2] == 0) 
     if (++data[1] == 0) if (++data[0] == 0) break; 
} 

Единственный подход, который я могу думать будет использовать небезопасный код, чтобы поговорить с массивом как будто это int64 ... грязный ,

unsafe static void Test() { 
    byte[] data = new byte[8]; 
    fixed (byte* first = data) { 
     ulong* value = (ulong*)first; 
     do { 
      // use data here 
      *value = *value + 1; 
     } while (*value != 0); 
    } 
} 
+0

+1: Да. Восемь байтов - Int64. :-) –

+0

Я думаю, что накладные расходы на исправление массива в памяти, чтобы использовать его в небезопасном коде, перевешивали бы выгоду от возможности рассматривать его как int64 ... – Guffa

+0

Вы должны использовать ulong * в небезопасном коде, а не uint *. Несмотря на то, что вы зацикливаетесь внутри фиксированного оператора, это удивительно медленно. Мой управляемый код для увеличения массива примерно в 200 раз быстрее ... – Guffa

-1

BitConverter.ToInt64/BitConverter.GetBytes - преобразующие 8 байт точно долго, и увеличивать его. Когда почти закончите преобразовать обратно в байты. Это самый быстрый способ в системе

+0

Когда * почти * сделано? –

+4

'BitConverter'? самый быстрый? Создание нового 'byte []' ** за звонок ** является ** не ** самым быстрым на любом растяжке. –

+0

Идея заключалась в том, чтобы сделать некоторые логические скобки - начать конвертировать (ONCE!) Байты в длину. Несколько раз увеличивайте столько, сколько сможете, в конце (WHEN ALMOST DONE и ONCE!) Конвертируйте обратно в байты – Dewfy

1
for (UInt64 i = 0; i < UInt64.MaxValue; i++) 
{ 
    byte[] data = BitConverter.GetBytes(i) 
} 
+0

Это создает новый 'byte []' за звонок, делая много работы для выделения и сбора мусора; есть более быстрые способы использования фиксированного массива –

+0

Этот цикл будет либо выполнен в кратчайшие сроки, либо весной 785 года. –

+0

Простое выполнение циклов займет около семи лет, используя более быстрый метод в моем ответе. Использование BitConverter займет около 10000 лет ... – Guffa

3

байт [8] является по существу ULONG, но если вам действительно нужно, чтобы быть байт [8] вы можете использовать

byte[] bytes = new byte[8]; 
ulong i = 0; 
bytes = BitConverter.GetBytes(i); 
6

Это, как вы увеличиваете значение в массиве:

int index = testKey.Length - 1; 
while (index >= 0) { 
    if (testKey[index] < 255) { 
     testKey[index]++; 
     break; 
    } else { 
     testKey[index--] = 0; 
    } 
} 

Когда index будет -1 после этого кода, вы итерацию все комбинации.

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

Edit:
Небольшой тест производительности показал, что это примерно 1400 раз быстрее, чем при использовании BitConverter ...

+4

Почему downvote? Если вы не объясните, почему, это нецелесообразно ... – Guffa

+0

Я поддержал, потому что вижу потенциал здесь. Проблема в том, что оператор 'break' находится не в том месте. As-код не будет проходить мимо 1. – LamonteCristo

+0

@ makerofthings7: Спасибо за upvote. Я думаю, что вы неправильно поняли код. Он увеличит массив на единицу. Чтобы увеличить его еще на один шаг, вы снова используете код. Если вы хотите использовать его в цикле, вы помещаете код в цикл. – Guffa

4

Какой большой вопрос! Вот способ сделать это без опасного кода:

public struct LongAndBytes 
{ 
    [FieldOffset(0)] 
    public ulong UlongValue; 
    [FieldOffset(0)] 
    public byte Byte0; 
    [FieldOffset(1)] 
    public byte Byte1; 
    [FieldOffset(2)] 
    public byte Byte2; 
    [FieldOffset(3)] 
    public byte Byte3; 
    [FieldOffset(4)] 
    public byte Byte4; 
    [FieldOffset(5)] 
    public byte Byte5; 
    [FieldOffset(6)] 
    public byte Byte6; 
    [FieldOffset(7)] 
    public byte Byte7; 

    public byte[] ToArray() 
    { 
     return new byte[8] {Byte0, Byte1, Byte2, Byte3, Byte4, Byte5, Byte6, Byte7}; 
    } 
} 


// ... 

    LongAndBytes lab = new LongAndBytes(); 

    lab.UlongValue = 0; 
    do { 
     // stuff 
     lab.UlongValue++; 
    } while (lab.ULongValue != 0); 

Каждый из членов Byte0 ... Byte7 перекрываться ULong и поделиться своим членам. Это не массив - я пробовал обдумывать это и имел неудовлетворительные результаты. Бьюсь об заклад, кто-то знает волшебную декларацию, чтобы это произошло. Я могу сделать это для P/Invoke, но не для использования в .NET, поскольку массив является объектом.

+1

'byte [] b = новый байт [8] {Byte0, Byte1, Byte2, Byte3, Byte4, Byte5, Byte6, Byte7};' – Chris

+0

спасибо! Добавлено изменение в – plinth

+0

+1 для awesomeness .. Мне нравится этот ответ, простой, но мощный. –

2

Вы можете извлечь байты с помощью битовых операторов:

byte[] bytes = new byte[8]; 
for (ulong u = 0; u < ulong.MaxValue; u++) 
{ 
    bytes[0] = (byte)(u & 0xff); 
    bytes[1] = (byte)((u >> 8) & 0xff); 
    bytes[2] = (byte)((u >> 16) & 0xff); 
    bytes[3] = (byte)((u >> 24) & 0xff); 
    bytes[4] = (byte)((u >> 32) & 0xff); 
    bytes[5] = (byte)((u >> 40) & 0xff); 
    bytes[6] = (byte)((u >> 48) & 0xff); 
    bytes[7] = (byte)((u >> 56) & 0xff); 
    // do your stuff... 
} 

Это меньше «хаком», так как он действует на беззнаковое 64-битное целое число, а затем извлечь байт. Однако будьте осторожны с CPU endianess.

1
byte[] array = new byte[8]; 
int[] shifts = new int[] { 0, 8, 16, 24, 32, 40, 48, 56 };  
for (long index = long.MinValue; index <= long.MaxValue; index++) 
{ 
    for (int i = 0; i < 8; i++) 
    { 
     array[i] = (byte)((index >> shifts[i]) & 0xff); 
    } 
    // test array 
} 
0
for (int i = 0; i < bytes.Length & 0 == ++bytes[i]; i++); 

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