摘要: 转载请标明原文地址:https://segmentfault.com/a/1190000021329368 一、简介 LiteByte是一种轻量级的二进制数据交换格式。 体积小巧、简单易用是设计目标,主要用于解决前后台数据传输的问题。 版本:0.13.2 作者:冰封百度(ZhangYu) 设计的灵感 阅读全文
posted @ 2019-12-20 14:47 冰封百度 阅读(541) 评论(0) 推荐(0) 编辑

转载文章请标明原文地址:https://segmentfault.com/a/1190000046149521

一、表示规则

1.内存排布

C#中的decimal类型占16字节,内存排布如下:
flags(32位 符号1位+缩放因子8位)|high(32位)|low + mid(64位)
S0000000 CCCCCCCC 00000000 00000000 | HHHHHHHH HHHHHHHH HHHHHHHH HHHHHHHH | LLLLLLLL LLLLLLLL LLLLLLLL LLLLLLLL | MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM

2.关键源码

Decimal源码

private const int SignMask = unchecked((int)0x80000000);
// NOTE: Do not change the order and types of these fields. The layout has to
// match Win32 DECIMAL type.
private readonly int _flags;
private readonly uint _hi32;
private readonly ulong _lo64;

public Decimal(int lo, int mid, int hi, bool isNegative, byte scale)
{
    ArgumentOutOfRangeException.ThrowIfGreaterThan(scale, 28);
    _lo64 = (uint)lo + ((ulong)(uint)mid << 32);
    _hi32 = (uint)hi;
    _flags = ((int)scale) << 16;
    if (isNegative)
        _flags |= SignMask;
}

二、代码实现

1.decimal转二进制

private static byte[] WriteDecimal(decimal value) {
    /*
    // 推荐用decimal.GetBits(value) 方法获取decimal的四个部分 这里为了性能更好 就用了指针直接读内存
    int[] parts = decimal.GetBits(value);
    int low = parts[0];
    int mid = parts[1];
    int high = parts[2];
    int flags = parts[3];
    */
    uint flags;
    uint high;
    uint low;
    uint mid;
    unsafe {
        // Decimal源码:int _flags; uint _hi32; ulong _lo64; _lo64 = (uint)lo + ((ulong)(uint)mid << 32);
        uint* ptr = (uint*)&value;
        flags = ptr[0]; // int _flags
        high = ptr[1];  // uint _hi32
        low = ptr[2];   // ulong _lo64 低32位
        mid = ptr[3];   // ulong _lo64 高32位
    }
    bool isNegative = (flags & 0x80000000) != 0; // 取flags的最高位(0为非负值 1为负值)
    byte scale = (byte)((flags >> 16) & 0x1F);   // 取flags第17位开始的低8位(最大数值28)
    byte[] bytes = new byte[14];
    bytes[0] = isNegative ? (byte)1 : (byte)0;
    bytes[1] = scale;
    bytes[2] = (byte)low;
    bytes[3] = (byte)(low >> 8);
    bytes[4] = (byte)(low >> 16);
    bytes[5] = (byte)(low >> 24);
    bytes[6] = (byte)mid;
    bytes[7] = (byte)(mid >> 8);
    bytes[8] = (byte)(mid >> 16);
    bytes[9] = (byte)(mid >> 24);
    bytes[10] = (byte)high;
    bytes[11] = (byte)(high >> 8);
    bytes[12] = (byte)(high >> 16);
    bytes[13] = (byte)(high >> 24);
    return bytes;
}

2.二进制转decimal

private static decimal ReadDecimal(byte[] bytes) {
    bool isNegative = bytes[0] != 0;
    byte scale = bytes[1];
    int low = bytes[2] | bytes[3] << 8 | bytes[4] << 16 | bytes[5] << 24;
    int mid = bytes[6] | bytes[7] << 8 | bytes[8] << 16 | bytes[9] << 24;
    int high = bytes[10] | bytes[11] << 8 | bytes[12] << 16 | bytes[13] << 24;
    return new decimal(low, mid, high, isNegative, scale);
}

三、总结

1.精度丢失问题

decimal不会产生精度丢失问题。因为decimal是基于十进制的科学计数法表示的、与float和double的基于二进制科学计数法表示的规则不同,所以不会产生精度丢失问题,在对小数计算敏感的场景里,建议用decimal代替float和double。

2.内存排布问题

decimal内存排布由于实现方式的原因,并不是flags、high、mid、low这种排布方法,用指针获取值时需要注意。

3.序列化和网络传输问题

由于不同编程语言中,类似decimal类型的定义标准和实现原理差异巨大,所以decimal的序列化和网络传输建议转为字符串,字符串可以在不同语言之间转为decimal类型。

posted @ 2025-02-26 12:11 冰封百度 阅读(3) 评论(0) 推荐(0) 编辑
摘要: ieee754 float浮点数二进制表示方法 阅读全文
posted @ 2025-02-15 08:51 冰封百度 阅读(35) 评论(0) 推荐(0) 编辑
摘要: C# sizeof计算规则 计算方法 阅读全文
posted @ 2022-04-18 23:14 冰封百度 阅读(804) 评论(0) 推荐(0) 编辑
摘要: 转载请标明原文地址:http://www.cnblogs.com/zhangyukof/p/7068615.html 1.Unity下载安装和破解方法: http://blog.sina.com.cn/s/blog_4ae08c340102weu1.html 2.Unity脚本API参考手册和脚本常 阅读全文
posted @ 2017-06-23 10:20 冰封百度 阅读(1478) 评论(1) 推荐(0) 编辑
摘要: 匹配单行和多行注释: 匹配空白行: 匹配换行符: 匹配空白符: 阅读全文
posted @ 2017-06-14 16:18 冰封百度 阅读(2579) 评论(0) 推荐(0) 编辑
摘要: Unity5优秀插件 阅读全文
posted @ 2017-05-10 14:58 冰封百度 阅读(570) 评论(0) 推荐(0) 编辑
摘要: Unity各平台宏定义 阅读全文
posted @ 2017-05-10 14:00 冰封百度 阅读(3315) 评论(0) 推荐(0) 编辑
摘要: 转载请标明原文地址:http://www.cnblogs.com/zhangyukof/p/6835582.html Unity5中文脚本手册 网页版 Unity API 执行顺序: Unity5中文用户手册 网页版Unity5中文组件手册 网页版 阅读全文
posted @ 2017-05-10 13:50 冰封百度 阅读(10942) 评论(0) 推荐(0) 编辑
摘要: 面向对象的一些基础概念 阅读全文
posted @ 2017-05-09 11:31 冰封百度 阅读(544) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示