@SergeySerge11

Как с помощью SIMD векторизации из массива float сделать bit массив знаковых битов?

допустим есть массив -999 0 -9 -1 2 3 -1
Как из него получить битовое представление 0100110 Или хотя бы Байтное.

var r = new Random(1);
int n = 100_000_000; 
float[] arr = Enumerable.Range(0, n).Select<int, float>(e => r.NextSingle() * 2f - 1f).ToArray();
byte[]arrBytes = new byte[arr.Length]; 
{
    

  
        for (int i = 0; i < n; i++)
        {
            if (arr[i] >= 0)
                arrBytes[i] = 0;
            else
                arrBytes[i] = 1;

       }
   
}
{
    
 
        for (int i = 0; i < n; i++)
        {
            arrBytes[i]=((byte)(1 - (BitConverter.SingleToInt32Bits(arr[i]) >>> 31)));

        }
 
}

'Как сделать векторизованное SIMD с Avx2 решение задачи из кода выше
Примерно как-то так, но как убрать последний цикл, и заменить его Avx операцией,
int len = Vector256<float>.Count;
for (int i = 0; i < n; i+= len)
{ 
    var inputVector = Vector256.LoadUnsafe<float>(ref arr[i]);
    var result = Vector256.ShiftRightLogical(inputVector.AsInt32(), 31);
    
    for (int t = 0; t < len; t++)
    {
        arrBytes[i + t] =1- (byte)result[t]; 
    }
   
}

К примеру 1 версия работает в 5-10 раз дольше чем ниже, этот должен еще в раза 4 по идеи работать,
Если кому интересно сделал вот так, очень страшное извлечение адреса, ради копирования. Но так быстрее. Кастомный метод CopyTo ломает алгоритм
int len = Vector128<float>.Count;
            byte[] arrMasks = {
             0,4,8,12 
            };
            Vector128<byte> mask = Vector128.LoadUnsafe<byte>(ref arrMasks[0]);
            for (int i = 0; i < n; i += len)
            {
                var inputVector = Vector128.LoadUnsafe<float>(ref arr[i]);
                var result = Vector128.ShiftRightLogical(inputVector.AsInt32(), 31);
                var  res  =  (Avx2.Shuffle(result.AsByte(), mask));
               void*ptr=Unsafe.AsPointer<Vector128<byte>>(ref res);
                int* ptrInt=(int*)Unsafe.Add<byte>(ptr, 0);  
                var p = (int*) Unsafe.AsPointer<byte>(ref arrBytes[i]);
                *p = *ptrInt;  
            }

Бенчмарк, там соотношение
15
2.6
1
в 15 раз разница .
  • Вопрос задан
  • 120 просмотров
Решения вопроса 1
mindtester
@mindtester Куратор тега C#
http://iczin.su/hexagram_48
для начального хода мыслей
var floatArray = new float[] { -999, 0, -9, -1, 2, 3, -1 };
var bits = 0x00000000;

int check(float f) => (f >= 0) switch
{
    (true) => 1,
    _ => 0
};

string tobin(int i) => Convert.ToString(i, 2);

foreach (var f in floatArray)
{
    Console.Write(f);
    Console.Write($";\t{check(f)}");
    Console.Write($";\t{tobin(bits)}");
    bits = bits | (check(f) & 0x1);
    bits <<= 1;
    Console.WriteLine($";\t{tobin(bits)}");
}
.. хотя, если еще подумать.. вторичное маскирование излишне..
var floatArray = new float[] { -999, 0, -9, -1, 2, 3, -1 };
var bits = 0x00000000;

int check(float f) => (f >= 0) switch
{
    (true) => 1,
    _ => 0
};

string tobin(int i) => Convert.ToString(i, 2);

foreach (var f in floatArray)
{
    Console.Write(f);
    Console.Write($";\t{check(f)}");
    Console.Write($";\t{tobin(bits)}");
    bits = bits | check(f);
    bits <<= 1;
    Console.WriteLine($";\t{tobin(bits)}");
}
тат так так.. место сдвига важно!.. (выше по сути ошибка логики).. см итог
var floatArray = new float[] { -999, 0, -9, -1, 2, 3, -1 };
var bits = 0x00000000;

int check(float f) => (f >= 0) switch
{
    (true) => 1,
    _ => 0
};

string tobin(int i) => Convert.ToString(i, 2);

foreach (var f in floatArray)
{
    bits <<= 1;
    Console.Write($"{f};\t{check(f)};\t{tobin(bits)}");
    bits |= check(f);
    Console.WriteLine($";\t{tobin(bits)}");
}

ps SergeySerge11, а какая размерность вектора? если мегабайты, то может и имеет смысл. но если в предела 8, 16, 32 бит - из пушки по воробьям!
мало того SIMD зависит от железа, а байткод нет
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы