如何在C#中确定泛型整数数据类型所需的位数?
获取IBinaryInteger类型的二进制位数(无需unsafe)
针对.NET 7中实现IBinaryInteger<T>的泛型整数类型,要在不使用unsafe编译的sizeof的前提下获取其二进制位数,以下是几种更优雅的实现方案:
方案1:利用BitLength()方法(最推荐)
IBinaryInteger<T>继承自INumberBase<T>接口,该接口的BitLength()方法会返回表示当前值所需的最小二进制位数。对于T.AllBitsSet(所有位均为1的实例),这个值正好等于类型的总位数,再通过CreateChecked<int>安全转换为int类型:
using System.Numerics; static int CountBits<T>() where T : IBinaryInteger<T> { return T.CreateChecked<int>(T.AllBitsSet.BitLength()); }
方案2:修正PopCount实现
你之前尝试的PopCount思路是可行的,只需用IBinaryInteger提供的类型转换方法替代强制转换,将PopCount返回的T类型值安全转为int:
static int CountBits<T>() where T : IBinaryInteger<T> { return T.CreateChecked<int>(T.PopCount(T.AllBitsSet)); }
由于T.AllBitsSet的所有位都是1,PopCount的结果就是类型的总位数,CreateChecked会在转换溢出时抛出异常,保证类型安全。
方案3:通过Log2计算位数
利用Log2方法获取最高有效位的索引,加1后得到总位数,再转换为int:
static int CountBits<T>() where T : IBinaryInteger<T> { return T.CreateChecked<int>(T.Log2(T.AllBitsSet) + T.One); }
该方案对无符号和有符号的IBinaryInteger实现类型均适用,即使是有符号类型的AllBitsSet(补码表示的-1),Log2也能正确计算最高位位置。
现有方案的局限性说明
- 原
GetByteCount()*8方案:仅支持位数为8的倍数的类型,自定义非8倍数位数的类型(如UInt7)会返回错误结果。 - 循环计数方案:虽然功能正常,但性能略逊(例如UInt128需要循环128次),且代码简洁度不足。
内容的提问来源于stack exchange,提问作者BoCoKeith
相关产品推荐
相关产品推荐

