Csharp - 将单个转换为十进制而不转换为字符串

时间:2017-03-03 22:14:12

标签: c# .net decimal

我从OdcDataReader获取一个单独类型的值。我不想在代码中使用单个代码,因此我想将其转换为小数。但是,似乎无论何时我尝试将其强制转换为十进制(或任何相关的东西),它都会丢失几个小数位。我需要尽可能准确地计算我的计算量。我能找到的唯一方法是将单个转换为带有'R'参数的字符串(Round Trip),然后将字符串解析为小数。我创建了一些扩展方法来转换它们但我希望有一种方法来转换它们而不需要字符串转换和解析。请记住,我需要保持精确度。

Single sng = 1.32397970f;       // 1.32397974
decimal d = (decimal)sng;       // 1.32398M
d = Convert.ToDecimal(sng);     // 1.32398M
string xxx = sng.ToString("G"); // "1.32398"
xxx = sng.ToString("C");        // "$1.32"
xxx = sng.ToString("E");        // "1.323980E+000"
xxx = sng.ToString("e");        // "1.323980e+000"
xxx = sng.ToString("F");        // "1.32"
xxx = sng.ToString("G");        // "1.32398"
xxx = sng.ToString("N");        // "1.32"
xxx = sng.ToString("P");        // "132.40 %"
xxx = sng.ToString("R");        // "1.32397974" - Bingo!

// My extension methods
static class ExtensionMethods
{
    public static decimal ToDecimal(this Single value)
    {
        decimal d = decimal.Parse(value.ToString("R"));
        return d;
    }

    public static decimal ToDecimal(this Single? value, decimal dflt)
    {
        if (!value.HasValue)
            return dflt;

        decimal d = decimal.Parse(value.Value.ToString("R"));
        return d;
    }

    public static decimal? ToDecimal(this Single? value)
    {
        if (!value.HasValue)
            return null;

        decimal d = decimal.Parse(value.Value.ToString("R"));
        return d;
    }
}

3 个答案:

答案 0 :(得分:2)

转换它先做一个双倍,然后再做十进制,你会得到更多"精度"。

for k, v in thevalues.items():
    for i in thevalues[k]:
        print(myclass('c + d',.......).execute())

尽管如此,你将获得比实际单个值更高的精度。

答案 1 :(得分:1)

你可以做下面的事情:

decimal d = Convert.ToDecimal((double)sng);

会给你结果:

  

1,32397973537445

答案 2 :(得分:1)

我认为以下内容将满足您的标准,即使我发现使用Single作为货币值也很奇怪。该方法基于有限的测试成功地使该值往返。该技术基于将有效位的最大数量限制为9,因为这是IEEE 754单精度二进制浮点值的最大值。

Single sng = 1.32397970f;
Decimal dec = SingleToDecimal(sng);
Single sng2 = Convert.ToSingle(dec);
bool b = sng.Equals(sng2);  
 private static decimal SingleToDecimal(float s)
 {
    // From: IEEE 754 single-precision binary floating-point format: binary32
    // https://en.wikipedia.org/wiki/Single-precision_floating-point_format#IEEE_754_single-precision_binary_floating-point_format:_binary32

    // The IEEE 754 standard specifies a binary32 as having:

    //    Sign bit: 1 bit
    //    Exponent width: 8 bits
    //    Significand precision: 24 bits (23 explicitly stored)

    //This gives from 6 to 9 significant decimal digits precision
    const int maxSignificantDigits = 9;

    decimal sign = (s < 0F) ? decimal.MinusOne : decimal.One;
    s = Math.Abs(s);

    double whole = Convert.ToDouble(Math.Floor(s));
    double fraction = s - whole;

    int roundOffDigits = 0;
    if (whole > 0)
    {
        int numDigitsInWhole = Convert.ToInt32(Math.Floor(Math.Log10(whole))) + 1;
        roundOffDigits = maxSignificantDigits - numDigitsInWhole;
    }
    else
    {
        int numLeadZerosInFraction = Convert.ToInt32(Math.Floor(-Math.Log10(fraction)));
        roundOffDigits = maxSignificantDigits + numLeadZerosInFraction;
    }

    fraction = Math.Round(fraction, roundOffDigits, MidpointRounding.ToEven);

    return new decimal(fraction + whole) * sign;
 }