使最小和最接近的数字为零-C#

本文关键字:数字 -C# 最接近 | 更新日期: 2023-09-27 18:27:50

如何使用C#将最小数和最近数归零?例如,最小且最接近零的十进制(DOUBLE)数在一台电脑上可能为0.000009,在另一台电脑中可能为0.0000000000000000001。

我的意思是1/The_Most_LONG_INTEGER的"最可能的结果"。

如何获取?

使最小和最接近的数字为零-C#

我想你的意思是计算你的机器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);
                }
            }
        }
    }