來源:
嗚嗚喔學習筆記
搜尋此網誌
2023年10月1日 星期日
2023年9月14日 星期四
C# int[] to byte[] , byte[] to int[]
public class ByteAyParser
{
public static byte[] IntAy2ByteAy(int[] intAy)
{
int byteCount = intAy.Length * 4;
byte[] byteAy = new byte[byteCount];
for (int i = 0; i < intAy.Length; i++)
{
int val = intAy[i];
byteAy[i * 4 + 3] = (byte)((val >> 24) & 0xFF);
byteAy[i * 4 + 2] = (byte)((val >> 16) & 0xFF);
byteAy[i * 4 + 1] = (byte)((val >> 8) & 0xFF);
byteAy[i * 4 + 0] = (byte)(val & 0xFF);
}
return byteAy;
}
public static int[] ByteAy2IntAy(byte[] byteAy)
{
if (byteAy.Length % 4 != 0)
{
Debug.LogErrorFormat("ByteAy2IntAy byteAy.Length {0} not a multiple of 4", byteAy.Length);
return null;
}
int intCount = byteAy.Length >> 2;// 除4
int[] intArray = new int[intCount];
for (int i = 0; i < intCount; i++)
{
int val = 0;
val |= byteAy[i * 4 + 3] << 24;
val |= byteAy[i * 4 + 2] << 16;
val |= byteAy[i * 4 + 1] << 8;
val |= byteAy[i * 4];
intArray[i] = val;
}
return intArray;
}
}
public class ByteAyParserTester
{
[Test]
public void IsMatch()
{
int[] intAy = new int[] { -1, 0, 1, };
byte[] bAy = ByteAyParser.IntAy2ByteAy(intAy);
int[] intAyBack = ByteAyParser.ByteAy2IntAy(bAy);
for (int i = 0; i < intAy.Length; i++)
{
if (intAy[i] != intAyBack[i])
{
Debug.LogErrorFormat("No Match intAy[{0}] {1} , intAyBack[{0}] {2}", i, intAy[i], intAyBack[i]);
Assert.Fail();
}
}
}
[Test]
public void IsMatchLimit()
{
int[] intAy = new int[] { int.MinValue, int.MinValue };
byte[] bAy = ByteAyParser.IntAy2ByteAy(intAy);
int[] intAyBack = ByteAyParser.ByteAy2IntAy(bAy);
for (int i = 0; i < intAy.Length; i++)
{
if (intAy[i] != intAyBack[i])
{
Debug.LogErrorFormat("No Match intAy[{0}] {1} , intAyBack[{0}] {2}", i, intAy[i], intAyBack[i]);
Assert.Fail();
}
}
}
}
2023年8月31日 星期四
C# Return Mutiple Value , C# 回傳多個值
結論:
ValueTuple<int, int> 等價於 (int,int) 不可定義變數名稱
out int a , out int b 舊版C#適用
Tuple<int, int> Reference Type 不建議使用 會GC
範例:
使用(int,int)最佳 , 沒GC可讀性高 可定義變數名稱
ValueTuple<int, int> 等價於 (int,int) 不可定義變數名稱
out int a , out int b 舊版C#適用
Tuple<int, int> Reference Type 不建議使用 會GC
範例:
// ValueTuple<int, int> 屬於 Value Type , 不會產生 GC
public ValueTuple<int, int> GET3()
{
return new ValueTuple<int, int>(1, 2);
}
// ValueTuple<int, int> 等價於 (int, int) 屬於語法糖 可以互轉
public (int a, int b) GET1()
{
return (1, 2);
}
// ValueTuple<int, int> 等價於 (int, int) 屬於語法糖 可以互轉
public ValueTuple<int, int> GET4()
{
//簡易寫法
return (1, 2);
}
public (int a, int b) GET2()
{
//可自定義變數名稱 可讀性比較好
(int a, int b) val;
val.a = 1;
val.b = 2;
return val;
}
// Tuple<int,int> 屬於 Reference Type , 會產生 GC
public Tuple<int, int> GET5()
{
return new Tuple<int, int>(1, 2);
}
// 用 out 參數直接改值
public void GET(out int a, out int b)
{
a = 1;
b = 2;
}
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:
在資料集中情況下壓縮比還不錯 , 依據資料格式類型壓縮到上百倍也不是問題
未來: 可加入平行化處理 加速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日 星期一
C# Rotation to Positive , [C#] 旋轉角度轉正 不給負數
public static float ClampRotaionY(float y)
{
while (y < 0)
{
y += 360;
}
while (y > 360)
{
y -= 360;
}
return y;
}
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
訂閱:
文章 (Atom)