嗚嗚喔學習筆記

搜尋此網誌

2023年8月21日 星期一

C# Hex256 Array , Easy to Search.

 




    Hex256 = new string[]{
    "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
    "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
    "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
    "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
    "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
    "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
    "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
    "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
    "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
    "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
    "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
    "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
    "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
    "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
    "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
    "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" };


2023年7月6日 星期四

C# - run-length encoding - RLE - Unity ( For byte or Ushort )

這段CODE只處理連續byte資料 或是連續ushort資料 非string版本
在資料集中情況下壓縮比還不錯 , 依據資料格式類型壓縮到上百倍也不是問題
未來: 可加入平行化處理 加速Encode 跟 Decode

各種演算法參考資料
Run Length Encoding 參考資料

其他壓縮法簡單比較:
CodeTree ( 四元樹演算法 O(n)
LZMA ( 對重複的組合 壓縮比較有效 可平行化 O(n)
RunLen ( 目前使用 實作簡單 可平行化 適合資料單一結構 O(n)
QOI (針對圖片地壓縮格式 純資料可能沒這麼好
Huffman Compression ( 把重複地編碼建表 再來壓縮

Code:


using System;
using System.Collections.Generic;


public class RunLengthCompression
{
    public byte[] EncodeUshort(ushort[] bAy)
    {
        if (bAy == null)
        {
            return null;
        }

        List codeList = new List();
        for (int i = 0; i < 4; i++)
        {
            codeList.Add(0);
        }

        byte count = 1;
        for (int i = 0; i < bAy.Length - 1; i++)
        {
            ushort now = bAy[i];
            ushort next = bAy[i + 1];
            if (now.Equals(next))
            {
                count++;
                if (count == 255 || i >= bAy.Length - 2)
                {
                    AddUshort(codeList, now);
                    codeList.Add(count);
                    count = 0;
                }
            }
            else
            {
                if (count == 255)
                {
                    AddUshort(codeList, now);
                    codeList.Add(count);
                }
                else if (i >= bAy.Length - 2)
                {
                    AddUshort(codeList, now);
                    codeList.Add(count);

                    AddUshort(codeList, next);
                    codeList.Add(1);
                }
                else
                {
                    AddUshort(codeList, now);
                    codeList.Add(count);
                    count = 1;
                }
            }
        }

        byte[] result = codeList.ToArray();
        byte[] grouptCountBytes = BitConverter.GetBytes(bAy.Length);
        for (int i = 0; i < 4; i++)
        {
            result[i] = grouptCountBytes[i];
        }

        return result;
    }
    public ushort[] DecodeUshort(byte[] bAy, ushort[] ogAy = null)
    {
        byte header = 4;
        if (bAy == null || bAy.Length < 4)
        {
            return null;
        }

        int orginLen = BitConverter.ToInt32(bAy, 0);
        ushort[] result = new ushort[orginLen];
        int idx = 0;
        for (int i = header; i < bAy.Length; i += 3)
        {
            ushort val = GetUshort(bAy, i);
            byte count = bAy[i + 2];
            for (int j = 0; j < count; j++)
            {
                if (idx >= orginLen)
                {
                    ErrorLog("over idx ?");
                    break;
                }

                result[idx] = val;
                if (ogAy != null && ogAy[idx] != result[idx])
                {
                    ErrorLog($"not same in {idx}");
                    break;
                }
                idx++;
            }
        }
        return result;
    }
    private void AddUshort(List list, ushort val)
    {
        list.Add((byte)val);
        list.Add((byte)(val >> 8));
    }
    private ushort GetUshort(byte[] bAy, int idx)
    {
        ushort val = (ushort)((bAy[idx]) + (bAy[idx + 1] << 8));
        return val;
    }

    public byte[] Encode(byte[] bAy)
    {
        if (bAy == null)
        {
            return null;
        }

        List codeList = new List();
        for (int i = 0; i < 4; i++)
        {
            codeList.Add(0);
        }

        byte count = 1;
        for (int i = 0; i < bAy.Length - 1; i++)
        {
            byte now = bAy[i];
            byte next = bAy[i + 1];
            if (now == next)
            {
                count++;
                if (count == 255 || i >= bAy.Length - 2)
                {
                    codeList.Add(now);
                    codeList.Add(count);
                    count = 0;
                }
            }
            else
            {
                if (count == 255)
                {
                    codeList.Add(now);
                    codeList.Add(count);
                }
                else if (i >= bAy.Length - 2)
                {
                    codeList.Add(now);
                    codeList.Add(count);

                    codeList.Add(next);
                    codeList.Add(1);
                }
                else
                {
                    codeList.Add(now);
                    codeList.Add(count);
                    count = 1;
                }
            }
        }

        int orginLen = bAy.Length;
        codeList[0] = (byte)orginLen;
        codeList[1] = (byte)(orginLen >> 8);
        codeList[2] = (byte)(orginLen >> 16);
        codeList[3] = (byte)(orginLen >> 24);

        byte[] result = codeList.ToArray();
        return result;
    }
    public byte[] Decode(byte[] bAy, byte[] ogAy = null)
    {
        byte header = 4;
        if (bAy == null || bAy.Length < 4)
        {
            return null;
        }
        int orginLen = (bAy[3] << 24) | (bAy[2] << 16) | (bAy[1] << 8) | bAy[0];

        byte[] result = new byte[orginLen];
        int idx = 0;
        for (int i = header; i < bAy.Length; i += 2)
        {
            byte val = bAy[i];
            byte count = bAy[i + 1];
            for (int j = 0; j < count; j++)
            {
                if (idx >= orginLen)
                {
                    ErrorLog("over idx ?");
                    goto ERROR;
                }

                result[idx] = val;
                if (ogAy != null && ogAy[idx] != result[idx])
                {
                    ErrorLog($"not same in {idx}");
                    goto ERROR;
                }
                idx++;
            }
        }
        return result;

    ERROR:
        {
            return null;
        }
    }
    public static void TestCase(byte[] orgin)
    {
        RunLengthCompression compreesion = new RunLengthCompression();

        byte[] encode = compreesion.Encode(orgin);
        byte[] decode = compreesion.Decode(encode);

        if (orgin.Length != decode.Length)
        {
            ErrorLog("not same len");
        }

        for (int i = 0; i < orgin.Length; i++)
        {
            if (orgin[i] != decode[i])
            {
                ErrorLog($"not same [{i}] ,{orgin[i]},{decode[i]}");
                continue;
            }
        }
    }
    public static void TestCase(ushort[] orgin)
    {
        RunLengthCompression compreesion = new RunLengthCompression();

        byte[] encode = compreesion.EncodeUshort(orgin);
        ushort[] decode = compreesion.DecodeUshort(encode);

        if (orgin.Length != decode.Length)
        {
            ErrorLog("not same len");
        }

        for (int i = 0; i < orgin.Length; i++)
        {
            if (orgin[i] != decode[i])
            {
                ErrorLog($"not same [{i}] ,{orgin[i]},{decode[i]}");
                continue;
            }
        }
    }

    static void ErrorLog(string errorLog, params string[] p)
    {
        UnityEngine.Debug.LogErrorFormat(errorLog, p);
    }
}


Test Code:


    using NUnit.Framework;

public class RunLengthCompressionTester
{
    [Test]
    public void ByteUshort123()
    {
        RunLengthCompression.TestCase(new ushort[] { 1, 2, 3 });
    }

    [Test]
    public void ByteUshort1212()
    {
        RunLengthCompression.TestCase(new ushort[] { 1, 2, 1, 2 });
    }

    [Test]
    public void ByteUshort655_655_1_1()
    {
        RunLengthCompression.TestCase(new ushort[] { 655, 655, 1, 1 });
    }
    [Test]
    public void ByteUshort1111_9999_9999_9999()
    {
        RunLengthCompression.TestCase(new ushort[] { 1111, 9999, 9999, 9999 });
    }

    [Test]
    public void Ushort6666Reapeat257Times()
    {
        ushort[] b = new ushort[257];
        for (int i = 0; i < 257; i++)
        {
            b[i] = 6666;
        }

        RunLengthCompression.TestCase(b);
    }

    [Test]
    public void Ushort6666Reapeat513Times()
    {
        ushort[] b = new ushort[513];
        for (int i = 0; i < 513; i++)
        {
            b[i] = 6666;
        }

        RunLengthCompression.TestCase(b);
    }

    [Test]
    public void Byte123()
    {
        RunLengthCompression.TestCase(new byte[] { 1, 2, 3 });
    }
    [Test]
    public void Byte1212()
    {
        RunLengthCompression.TestCase(new byte[] { 1, 2, 1, 2 });
    }
    [Test]
    public void Byte122()
    {
        RunLengthCompression.TestCase(new byte[] { 1, 2, 2 });
    }
    [Test]
    public void Byte1122()
    {
        RunLengthCompression.TestCase(new byte[] { 1, 1, 2, 2 });
    }
    [Test]
    public void Byte1112()
    {
        RunLengthCompression.TestCase(new byte[] { 1, 1, 1, 2 });
    }
    [Test]
    public void Byte12123()
    {
        RunLengthCompression.TestCase(new byte[] { 1, 2, 1, 2, 3 });
    }
    [Test]
    public void Byte12344()
    {
        RunLengthCompression.TestCase(new byte[] { 1, 2, 3, 4, 4 });
    }
    [Test]
    public void Byte257()
    {
        byte[] b = new byte[257];
        for (int i = 0; i < 256; i++)
        {
            b[i] = 1;
        }

        b[256] = 2;
        RunLengthCompression.TestCase(b);
    }
    [Test]
    public void Byte258()
    {
        byte[] b = new byte[258];
        for (int i = 0; i < 256; i++)
        {
            b[i] = 1;
        }

        b[256] = 2;
        b[257] = 2;
        RunLengthCompression.TestCase(b);
    }
    [Test]
    public void Byte259()
    {
        byte[] b = new byte[259];
        for (int i = 2; i < 259; i++)
        {
            b[i] = 1;
        }

        b[0] = 2;
        b[1] = 2;
        RunLengthCompression.TestCase(b);
    }
    [Test]
    public void Byte515()
    {
        byte[] b = new byte[515];
        for (int i = 2; i < 515; i++)
        {
            b[i] = 1;
        }

        b[0] = 2;
        b[1] = 2;
        RunLengthCompression.TestCase(b);
    }
}


2022年12月19日 星期一

2022年12月14日 星期三

GIT .gitignore 刷新方式


我们用GIT提交版本的时候,忽略文件有可能并不是不变的。但是对于后来加入到.gitignore中的文件,GIT默认还是不理睬它们的。因为GIT有一个缓存的机制。



下面是解决办法:

1、使用命令工具Git Bash,进入需要修改的工作目录。如C:/est

则输入

cd c:/test



2、重置所有缓存(注意后面有个.)

git rm -r --cached .



3、重新添加(注意后面有个.)

git add .



4、提交

git commit -m ".gitignore is now working"




如需转载请标明出处:http://blog.csdn.net/itas109
————————————————
版权声明:本文为CSDN博主「itas109」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/itas109/article/details/48156805

2022年12月13日 星期二

C# Byte To 4 Bit 用4bit儲存資料 可以節省一半空間


public static class HalfByteArray
{
    public static byte HalfByteAyGet(byte[] bAy, int idx)
    {
        int bIndex = idx / 2;
        if (idx % 2 == 0)
        {
            return (byte)(bAy[bIndex] >> 4);
        }
        else
        {
            return (byte)(bAy[bIndex] & 0b0000_1111);
        }
    }

    public static byte[] Byte2Half(byte[] og)
    {
        byte[] bAry = new byte[og.Length / 2];
        for (int i = 0; i < og.Length; i += 2)
        {
            byte HLv0 = og[i];
            byte HLv1 = og[i + 1];

            byte b = (byte)((HLv0 << 4) + HLv1);
            bAry[i / 2] = b;
        }
        return bAry;
    }

    public static void TestCase()
    {
        byte[] og = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
        byte[] halfB = Byte2Half(og);

        for (int i = 0; i < og.Length; i++)
        {
            byte back = HalfByteAyGet(halfB, i);
            UnityEngine.Assertions.Assert.AreEqual(back, og[i]);
        }
    }
}

2022年7月6日 星期三

C# Switch case vs if else 效能分析

先說結論 : Switch case 再Case數量 > 5 之後比 if else 還快 ( 但快非常少 )

為什麼? 他經過什麼轉換?

Switch Case 是語法糖 所以他會經過轉換 基本上就是轉成 if else 的形式 只是會做一些優化處理

以下為轉換程式碼

如果 case 是數字常數時->會轉成樹狀查詢

int a = 100;
switch(a)
{
    case 100 :
        Do();
        break;
    case 200 :
        Do();
        break;
    case 300 :
        Do();
        break;
    case 400 :
        Do();
        break;
    case 500 :
        Do();
        break;
    case 600 :
        Do();
        break;
    default :
        break;
}

轉成:

int num = 100;
int num2 = num;
int num3 = num2;
if (num3 <= 300)
{
    if (num3 != 100)
    {
        if (num3 != 200)
        {
            if (num3 == 300)
            {
                Do();
            }
        }
        else
        {
            Do();
        }
    }
    else
    {
        Do();
    }
}
else if (num3 <= 500)
{
    if (num3 != 400)
    {
        if (num3 == 500)
        {
            Do();
        }
    }
    else
    {
        Do();
    }
}
else if (num3 != 600)
{
    if (num3 == 700)
    {
        Do();
    }
}
else
{
    Do();
}

物件格式:

Object b = "100";
switch(b)
{
    case "100" :
        Do();
        break;
    case "200" :
        Do();
        break;
    case "300" :
        Do();
        break;
    case "400" :
        Do();
        break;
    case "500" :
        Do();
        break;
    case "600" :
        Do();
        break;
    case "700" :
        Do();
        break;
    default :
        break;
}

case 數量 >5 時 會先轉HashCode 所以能夠被樹狀查詢 ( 會比較快點 ) 轉成:

object obj = "100";
object obj2 = obj;
object obj3 = obj2;
string text = obj3 as string;
if (text == null)
{
    return;
}
uint num = <PrivateImplementationDetails>.ComputeStringHash(text);
if (num <= 1162866994)
{
    if (num != 147274918)
    {
        if (num != 731423408)
        {
            if (num == 1162866994 && text == "300")
            {
                Do();
            }
        }
        else if (text == "500")
        {
            Do();
        }
    }
    else if (text == "700")
    {
        Do();
    }
}
else if (num <= 2291914577u)
{
    if (num != 1731450012)
    {
        if (num == 2291914577u && text == "600")
        {
            Do();
        }
    }
    else if (text == "100")
    {
        Do();
    }
}
else if (num != 2855274715u)
{
    if (num == 3286718301u && text == "200")
    {
        Do();
    }
}
else if (text == "400")
{
    Do();
}

結論: 當switch case 是數字常數時會比較快 or 非數字常數要超過5個以上才會優化

參考:

https://sharplab.io/#v2:CYLg1APgAgTAjAWAFBQAwAIpwHQGED2ANoQKYDGALgJb4B2AzgNzJqZwAszKGW2AMlVoBHLlADMmGOlzoA3snSL0CpeMzt0ASQBmAUUL0SuAIaGAFAEoVi+UiX30giumPoAvOjipUXB0qraZq5uHl6oFnLoACL4lowAvtYOJAYkjoHBHjDeEbLRsRYJSfYphulB7h5iOZExcYl2fuilaQEVIejsNXl1hQ1NzanlmegArN359cVKLcOV6ABsE71FjYr9SklqUBqatBQAygDuVBRkABYmhqhwlkm2A04u7p7evk30J2fnQVZrDg8BkoyKY0mF0CBpkDJoUoUCAEYAJxIxgA1u9oSCytkMJD/tDFCs4QMkSj0cTgaD0NVcRS/ET8QTSWiMUCsWkurTGdCGQSHMzydyHOyxt4IXSHLy+UoBayBiKlqg8dKlFKVbKJSKAOzeZUqmFypnIlkS4AkbTGACuhGcevVxsFAw26y2Eh2Wn2x1OFyuJFQMDu/0BfiewVePjhn29P2MfwGwbZVPBdulaulGqF9hFOPFmaaab5Gb5Ippuf1Bol9iLBJFnLL+oLRrJhr8IvGXPLjeh1cxVMV9ZVXYRDpbDjNFuttsrMpHcOd6HnrvU6AA8vCAFbkQ5fH2gm6B+wJ+xrzeUdDwl4AIjCl9HUe+ZnhcaaR6aIuv3kvA9TBVHJNneaKO+OJfimfJDv+zaalSl40qB06Er+CHngBxYwZy8GAZKSFYVWqE1jB7aYZ2OHlj2iZlJeirEQ2pH6uR8owTqqA0YOdH2lBWHjlaNrfoW+F+POi7/NsGgnluXrfL6/oHkor6KOJZ4Xh4H4sXeO4/E+cLycKME3nxBIQU0DFvjBIEGTy7HpgJFFpLBn4WUCRl+CZrboQ5YGGVZ/GcWhlFEY5AzOfyNmMZR1GBfm3lNiaXHmjxU64TOvlNEJSRJAADoiVAAG7GBQaTur0sgNPEQA===