Нет простого способа заставить его разделить, как вы хотите, но вы можете обнаружить округление и исправить его.Поскольку мантисса decimal
составляет 96 бит, вы не можете удерживать ее в long
или double
, поэтому я использую объект .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