使最小和最接近的数字为零-C#
本文关键字:数字 -C# 最接近 | 更新日期: 2023-09-27 18:27:50
如何使用C#将最小数和最近数归零?例如,最小且最接近零的十进制(DOUBLE)数在一台电脑上可能为0.000009,在另一台电脑中可能为0.0000000000000000001。
我的意思是1/The_Most_LONG_INTEGER的"最可能的结果"。
如何获取?
我想你的意思是计算你的机器Epsilon(http://en.wikipedia.org/wiki/Machine_epsilon)。
可以通过几种方式进行计算,例如:
double machineEpsilon = 1.0d;
do {
machineEpsilon= machineEpsilon/ 2.0d;
}
while ((double)(1.0 + machineEpsilon) != 1.0);
我知道这是一个老问题,但这里有另一种可能的方法,试图避免迭代。基于浮点格式,您可以人工生成最小的分数。在C#中,大小为(双)=64:
-
对于正常数
public double GetMinNormalFraction() { double inf =double.PositiveInfinity ; unsafe { ulong Inf_UL = *((ulong*)&inf); ulong minFraction_UL = (Inf_UL ^ (Inf_UL << 1)) ^ ((1ul << 63) + 1ul); return *((double*)&minFraction_UL); //2.2250738585072019E-308 in my computer } }
-
对于次正规/非正规数
public double GetMinDenormalFraction() { unsafe { ulong unit = 1ul; return *((double*)&unit); //4.94065645841247E-324 in my computer } }
在Saverio Terracciano之前提出的机器epsilon算法中,您可以使用它们作为起点来检查这些值是否是最小值(记住,对于非正规分数,请更改为while ( machineEpsilon > 0.0);
)
编辑
为了完成,但已经不可能了,如果需要可以加到一个数字上的最小分数,而不仅仅是零,一般的方法是:
public double GetMinFractionCloseTo(double number)
{
//check if number is a denormal/subnormal number
if (double.IsNaN(number) || double.IsInfinity(number))
return 0.0; // or throw Exception,etc
unsafe
{
double inf = double.PositiveInfinity;
ulong Inf_UL = *((ulong*)&inf);
ulong Number_UL = *((ulong*)&number);
bool isDenormal = (Inf_UL & Number_UL) == 0;
if (isDenormal)
{
//MinFraction is always the same with denormals
ulong unit = 1ul;
return *((double*)&unit);
}
else //Normal number
{
//Detect if it's the last normal number close to zero
//(This can be skipped most of the times as it is very unlikely)
long maxLongValue = long.MaxValue;
ulong ExcludeSign= *((ulong*)&(maxLongValue));
ulong minFract_UL = (Inf_UL ^ (Inf_UL << 1)) | 1ul;
bool isLimitToDenormal = ((minFract_UL ^ Number_UL) & ExcludeSign) == 0;
if (isLimitToDenormal)
{
//MinFraction is always the same with denormals
ulong unit = 1ul;
return *((double*)&unit);
}
else
{
ulong ClosestValue_UL = Number_UL ^ 1ul;
double ClosestValue = *((double*)&(ClosestValue_UL));
return Math.Abs(number - ClosestValue);
}
}
}
}