Byte 배열을 Hex(16진수) 문자열로 변환하는 방법

호오. 자주 가는 사이트에 제목과 유사한 글이 올라와 있었습니다. 그 글을 공유하려다가… 이런 종류의 문제는 구현 자체가 어렵지는 않아서, 일종의 코드 경진을 해보면 어떨까 해서 올려봅니다.

문제] 8192 * 10000 바이트 배열을 난수로 생성 후, 이를 16진수 HEX 문자열로 변환한다.
최종 스코어는 다음과 같이 한다.

a = BitConverter.ToString(buffer).Replace(“-”, “”) 의 소요 시간
b = 자신이 만든 루틴의 소요 시간

score = a / b;

4개의 좋아요

질문 답변 카테고리 대신 자유 게시판 쪽으로 옮기시는 건 어떨까요?

3개의 좋아요

스코어는 제 컴퓨터에서 Release/Any CPU로 `1.795’ 입니다.

using System;
using System.Diagnostics;

// 8192 * 10000 바이트 배열을 난수로 생성
var size = 8192 * 10000;
var rand = new Random();
var buffer = new byte[size];
rand.NextBytes(buffer);

// a 시간 측정
var sw = Stopwatch.StartNew();
var aStr = BitConverter.ToString(buffer).Replace("-", "");
sw.Stop();

var a = sw.ElapsedMilliseconds;
Console.WriteLine($"a = {a} ms");

// b 시간 측정
sw = Stopwatch.StartNew();
var bc = new char[size * 2];
for (var i = 0; i < buffer.Length; i++)
{
    var index = i << 1;
    (bc[index], bc[index + 1]) = ToHexa(buffer[i]);
}
var bStr = new string(bc);
sw.Stop();

var b = sw.ElapsedMilliseconds;
Console.WriteLine($"b = {b} ms ");

// 처리 검증
var check = aStr == bStr;
Console.WriteLine($"Check : {check}");
if (check == true)
{
    var score = (double)a / b;
    Console.WriteLine($"score: {score}");
}
// -----
static (char, char) ToHexa(byte d)
{
    var a = (d & 0xF0) >> 4;
    var b = d & 0x0F;

    if (a < 10)
        a += '0';
    else
        a += 'A' - 10;
    if (b < 10)
        b += '0';
    else
        b += 'A' - 10;

    return ((char)a, (char)b);
}
1개의 좋아요

.NET Core 5 + Benchmark 테스트 결과입니다.

Score: 1690.9 / 186.5 = 9.066487935656836

re

변환 코드

const string table = "0123456789ABCDEF";

return string.Create(Size * 2, _buffer, static(span, buffer) =>
{
    for (int i = 0; i < Size; i++)
    {
        span[0] = table[(buffer[i] & 0xF0) >> 4];
        span[1] = table[buffer[i] & 0x0F];
        span = span.Slice(2);
    }
});

전체 테스트 코드

using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;

[SimpleJob(RuntimeMoniker.NetCoreApp50)]
public class ByteHex16
{
    private const int Size = 8192 * 10000;

    private byte[] _buffer;

    [GlobalSetup]
    public void Setup()
    {
        _buffer = new byte[Size];
        new Random().NextBytes(_buffer);
    }

    [Benchmark]
    public string BitConverter()
    {
        return System.BitConverter.ToString(_buffer).Replace("-", "");
    }

    [Benchmark]
    public string Dimohy()
    {
        var bc = new char[Size * 2];

        for (var i = 0; i < _buffer.Length; i++)
        {
            var index = i << 1;
            (bc[index], bc[index + 1]) = ToHexa(_buffer[i]);
        }

        return new string(bc);

        static (char, char) ToHexa(byte d)
        {
            var a = (d & 0xF0) >> 4;
            var b = d & 0x0F;

            if (a < 10)
                a += '0';
            else
                a += 'A' - 10;

            if (b < 10)
                b += '0';
            else
                b += 'A' - 10;

            return ((char)a, (char)b);
        }
    }

    [Benchmark]
    public string EvanChoi()
    {
        const string table = "0123456789ABCDEF";

        return string.Create(Size * 2, _buffer, static(span, buffer) =>
        {
            for (int i = 0; i < Size; i++)
            {
                span[0] = table[(buffer[i] & 0xF0) >> 4];
                span[1] = table[buffer[i] & 0x0F];
                span = span.Slice(2);
            }
        });
    }
}
6개의 좋아요