问个关于高精度除法的问题

MygodStudio 2012-02-24 07:54:26
输入一个分子、分母,类型为System.Numerics.BigInteger,再输入一个有效数字数,表示要保留的数目,多余的位四舍五入,如果除尽可以提前结束。求助一个高效算法……(无需考虑分母为0的情况)
...全文
122 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
MygodStudio 2012-02-25
  • 打赏
  • 举报
回复
3楼的那个我也想到了,但是BigInteger所指定的数可能很大,因此应该用哈希表,暂时还没做,而且有时可能会反而变慢。(需求精度较低时)
MygodStudio 2012-02-25
  • 打赏
  • 举报
回复

private static string DivideWithValidDigits(BigInteger d1, BigInteger d2, int n)
{
var log10 = Math.Floor(Math.Log10((double)(d1 / d2)));
var result = new StringBuilder(n);
var zeros = 0;
while (result.Length - zeros <= n)
{
var mod = d1 % d2;
if (result.Length - zeros >= n)
{
if ((d1 - mod) / d2 > 4)
{
var j = result.Length - 1;
while (j >= 0)
if (result[j] == '9')
{
result[j] = '0';
j--;
}
else
{
result[j]++;
break;
}
if (j < 0)
{
result.Insert(0, '1');
log10++;
}
}
break;
}
if (mod != 0)
{
result.Append((d1 - mod) / d2);
while (zeros < result.Length && result[zeros] == '0') zeros++;
d1 = mod * 10;
}
else
{
result.Append(d1 / d2);
while (zeros < result.Length && result[zeros] == '0') zeros++;
break;
}
}
var pos = (log10 < 0 ? 0 : Convert.ToInt32(log10)) + 1;
if (pos < result.Length) result.Insert(pos, '.');
return result.ToString();
}
}


写了一个,大家看看能不能改进……
threenewbee 2012-02-25
  • 打赏
  • 举报
回复
本质上说,如果两个整数相除,结果必然是有限小数(也可以理解为循环节为0的无限循环小数的特例)或者无限循环小数,且循环节长度不会超过分母的大小。所以,高效的算法就是用手算的方法确定循环节,之后再根据精度要求想要多少位就有多少位。
MygodStudio 2012-02-25
  • 打赏
  • 举报
回复
哪一个自带的除法?可以任意指定精确到小数点后几位的吗
MygodStudio 2012-02-25
  • 打赏
  • 举报
回复
问题基本解决,结贴散分。
MygodStudio 2012-02-25
  • 打赏
  • 举报
回复
突然想起来log10(a/b)=log10(a)-log10(b),改进下:

private static string DivideWithValidDigits(BigInteger molecular, BigInteger denominator, int validDigits)
{
var log10 = Math.Floor(BigInteger.Log10(molecular) - BigInteger.Log10(denominator));
var result = new StringBuilder(validDigits);
var zeros = 0;
while (result.Length - zeros < validDigits) // process digits
{
var mod = molecular % denominator;
if (mod != 0)
{
result.Append((molecular - mod) / denominator);
while (zeros < result.Length && result[zeros] == '0') zeros++;
molecular = mod * 10;
}
else
{
result.Append(molecular / denominator);
break;
}
}
if (result.Length - zeros >= validDigits) // process rounding
{
if ((molecular - molecular % denominator) / denominator >= 5)
{
var j = result.Length - 1;
while (j >= 0)
if (result[j] == '9')
{
result[j] = '0';
j--;
}
else
{
result[j]++;
break;
}
if (j < 0)
{
result.Insert(0, '1');
log10++;
}
}
}
var pos = (log10 < 0 ? 0 : Convert.ToInt32(log10)) + 1;
if (pos < result.Length) result.Insert(pos, '.');
return result.ToString();
}
MygodStudio 2012-02-25
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 qldsrx 的回复:]

var log10 = Math.Floor(Math.Log10((double)(d1 / d2)));
我感觉你这里强制类型转换可能会出错,会导致数据溢出。而且两个BigInteger相除,返回的结果还是BitInteger,就算强制转换也应该转化为Int32啊,怎么都不会是double类型。
[/Quote]
已更正并修改:

private static string DivideWithValidDigits(BigInteger d1, BigInteger d2, int n)
{
var log10 = Math.Floor(BigInteger.Log10(d1 / d2));
var result = new StringBuilder(n);
var zeros = 0;
while (result.Length - zeros <= n)
{
var mod = d1 % d2;
if (result.Length - zeros >= n)
{
if ((d1 - mod) / d2 > 4)
{
var j = result.Length - 1;
while (j >= 0)
if (result[j] == '9')
{
result[j] = '0';
j--;
}
else
{
result[j]++;
break;
}
if (j < 0)
{
result.Insert(0, '1');
log10++;
}
}
break;
}
if (mod != 0)
{
result.Append((d1 - mod) / d2);
while (zeros < result.Length && result[zeros] == '0') zeros++;
d1 = mod * 10;
}
else
{
result.Append(d1 / d2);
//while (zeros < result.Length && result[zeros] == '0') zeros++; // zeros will be no more used
break;
}
}
var pos = (log10 < 0 ? 0 : Convert.ToInt32(log10)) + 1;
if (pos < result.Length) result.Insert(pos, '.');
return result.ToString();
}
qldsrx 2012-02-25
  • 打赏
  • 举报
回复
.NET自带的除法不能满足需求吗?
qldsrx 2012-02-25
  • 打赏
  • 举报
回复
var log10 = Math.Floor(Math.Log10((double)(d1 / d2)));
我感觉你这里强制类型转换可能会出错,会导致数据溢出。而且两个BigInteger相除,返回的结果还是BitInteger,就算强制转换也应该转化为Int32啊,怎么都不会是double类型。

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧