C#如何在没有隐式舍入的情况下划分小数

时间:2010-12-09 05:23:25

标签: c# decimal division

在c#中执行两位小数的除法时,如果真正的数学结果不能精确地存储为十进制类型,则结果的最后一位将自动舍入。

我想编写一个执行除法的函数,即使最后一位数字总是向下舍入,即使最后一位数字通常会导致向上舍入。

我的函数将被声明为MyDivide(十进制a,十进制b)

例如MyDivide(2.0M,3.0M)=> 0.6666666666666666666666666666

而c#除法运算符将产生2.0M / 3.0M => 0.6666666666666666666666666667

感谢您提供任何帮助。

2 个答案:

答案 0 :(得分:3)

您将不得不自己实施long division。没有办法让内置部门为你做这件事(提示:你无法区分2m / 3m.6666666666666666666666666667m / 1m6666666666666666666666666667m / 10000000000000000000000000000m

答案 1 :(得分:2)

没有简单的方法让它按照你想要的方式划分,但是你可以检测到舍入并对其进行校正。由于decimal的尾数是96位,因此您无法将其保留在longdouble中,因此我使用.Net 4 BigInteger对象。我只是将分母和商的尾数相乘,并将其与分子进行比较(根据乘法结果的指数进行调整)。如果结果大于分子,那么除法必须从零舍入,所以我只需要从商中减去最低位的1。为此,我创建了一个十进制小数,其尾数为1,指数为指数的指数。

using System;
using System.Numerics;
using System.Collections.Generic;

namespace DivTest
{
    class Divide
    {
        public static decimal MyDivide(decimal numerator, decimal denominator)
        {
            var quotient = numerator / denominator;
            // turn decimals into mantissas (BigInts) and exponents
            int nExp, dExp, qExp;
            var nMan = MantissaOfDecimal(num, out nExp);
            var dMan = MantissaOfDecimal(denom, out dExp);
            var qMan = MantissaOfDecimal(quotient, out qExp);
            // multiply quotient times denominator and compare with numerator
            if (dMan * qMan > nMan * BigInteger.Pow(10, dExp + qExp - nExp))
            {
                // quotient was rounded away from zero, so subtract LSB
                // to round back toward zero
                quotient -= new decimal(1, 0, 0, quotient < 0, (byte)qExp);
            }
            return quotient;
        }

        static BigInteger MantissaOfDecimal(decimal d, out int exponent)
        {
            var ints = decimal.GetBits(d);
            exponent = (ints[3] >> 16) & 0xFF;
            var bytes = new List<byte>(13);
            // create a BigInteger containing the mantissa of the decimal value
            bytes.AddRange(BitConverter.GetBytes(ints[0]));
            bytes.AddRange(BitConverter.GetBytes(ints[1]));
            bytes.AddRange(BitConverter.GetBytes(ints[2]));
            bytes.Add(0); // avoid high bits being interpreted as negative
            return new BigInteger(bytes.ToArray());
        }

        static void Main()
        {
            decimal num = 2m, denom = 3m;
            Console.WriteLine("Divide:   " + num / denom);
            Console.WriteLine("MyDivide: " + MyDivide(num, denom));
        }
    }
}

上述程序的输出是:

Divide:   0.6666666666666666666666666667
MyDivide: 0.6666666666666666666666666666