为什么0.1 + 0.2
不等于 0.3
?为什么16777216f
等于 16777217f
?为什么金钱计算都推荐用decimal
?本文主要学习了解一下数字背后不为人知的存储秘密。
01、数值类型
C#中的数字类型主要包含两类,整数、小数,C#中的小数都为浮点(小)数。
void Main()
{
int a1 = 100;
int a2 = 0x0f; //15
var b2 = 0b11; //3
var x1 = 1; //整数值默认为int
var y1 = 1.1; //小数值默认为double
Add(1, 2.3); //3.3
Add(1, 3); //4
}
private T Add<T>(T x, T y) where T : INumber<T>
{
return x + y * x;
}
- 用
var
类型推断时,整数值默认为int
,小数值默认为double
。 .NET 7
新增的一个专门用来约束数字类型的接口 INumber<T>
,用来约束数字类型非常好用。
数值类型大多提供的成员:
🔸静态字段 | 说明 |
---|---|
MaxValue | 最大值常量,Console.WriteLine(int.MaxValue); //2147483647 |
MinValue | 最小值常量 |
🔸静态方法 | 说明 |
Parse、TryParse | 转换为数值类型,是比较常用的类型转换函数,参数NumberStyles 可定义解析的数字格式 |
Max、Min | 比较值的大小,返回最大、小的值,int.Max(1,100) //100 |
Abs | 计算绝对值 |
IsInfinity | 是否有效值,无穷值 |
IsInteger | 是否整数 |
IsNaN | 是否为NaN |
IsPositive | 是否零或正实数 |
IsNegative | 是否表示负实数 |
数值类型还有很多接口,如加、减、乘、除的操作符接口,作为泛型约束条件使用还是挺不错的。
🔸操作符接口 | 说明 |
---|---|
IAdditionOperators | 加法 |
ISubtractionOperators | 减法 |
IMultiplyOperators | 乘法 |
IDivisionOperators | 除法 |
public static T Power<T>(T v1, T v2) where T : INumber<T>,
IMultiplyOperators<T, T, T>, IAdditionOperators<T, T, T>
{
return v1 * v1 + v2 * v2;
}
02、小数、浮点数⁉
C#中的小数类型有float、double、decimal 都是浮点数,浮点 就是“ 浮动小数点位置”,小数位数不固定,小数部分、整数部分是共享数据存储空间的。相应的,自然也有定点小数,固定小数位数,在很多数据库中有定点小数,C#中并没有。
在编码中我们常用的浮点小数是float、double,经常会遇到精度问题,以及类似下面这些面试题。
- ❓ 为什么
0.1 + 0.2
不等于0.3
? - ❓ 为什么浮点数无法准确的表示
0.1
? - ❓ 为什么
16777216f
等于16777217f
?这里f
表示为float
。 - ❓ 为什么
32
位float
可以最大表示3.402823E38
,64
位double
可以最大表示1.79*E308
,那么点位数根本存不下啊? - ❓ 同样是32位,
float
的数据范围远超int
,为什么?
Console.WriteLine(0.1 + 0.2 == 0.3); //False
Console.WriteLine(16777216f == 16777217f); //True
Console.WriteLine(double.MaxValue); //1.7976931348623157E+308
Console.WriteLine(int.MaxValue); //2147483647
Console.WriteLine