我有兴趣为BigDecimal
编写数学函数(实际上,也是为了...
{4}用Delphi编写,
但这与此无关 - 在这个问题中,我使用Java BigDecimal
,因为更多的人都知道它
我的BigDecimal
非常相似。下面的测试代码是用Java编写的,并且在Delphi中工作正常
译文)。
我知道BigDecimal
并不快,但它非常准确。我不想使用一些现有的Java BigDecimal
数学库,尤其不是
因为这是我自己的BigDecimals
类型(在 Delphi 中)。
作为如何实现trig函数的一个很好的例子,我找到了以下简单的例子(但我遗忘了哪里,对不起)。它显然使用 MacLaurin系列用于计算BigDecimal的余弦,具有给定的精度。
这个精确度正是我的问题。下面的代码使用5的额外精度来计算结果,并且只在最后,它将其舍入到所需的精度。
我觉得5的额外精度很好,例如,目标精度高达50甚至更高,但不适用于cos(BigDecimal)
精度更高(例如,1000位数或更多)。不幸的是,我无法找到验证这一点的方法(例如,使用在线非常准确的计算器)。
最后,我的问题是:我是对的 - 对于较大的数字而言,5可能还不够 - 如果是的话,我如何计算或估算所需的额外精度?
示例代码计算public class BigDecimalTrigTest
{
private List _trigFactors;
private int _precision;
private final int _extraPrecision = 5; // Question: is 5 enough?
public BigDecimalTrigTest(int precision)
{
_precision = precision;
_trigFactors = new Vector();
BigDecimal one = new BigDecimal("1.0");
BigDecimal stopWhen = one.movePointLeft(precision + _extraPrecision);
System.out.format("stopWhen = %s\n", stopWhen.toString());
BigDecimal factorial = new BigDecimal(2.0);
BigDecimal inc = new BigDecimal(2.0);
BigDecimal factor = null;
do
{
factor = one.divide(factorial, precision + _extraPrecision,
BigDecimal.ROUND_HALF_UP); // factor = 1/factorial
_trigFactors.add(factor);
inc = inc.add(one); // factorial = factorial * (factorial + 1)
factorial = factorial.multiply(inc);
inc = inc.add(one); // factorial = factorial * (factorial + 1)
factorial = factorial.multiply(inc);
} while (factor.compareTo(stopWhen) > 0);
}
// sin(x) = x - x^3/3! + x^5/5! - x^7/7! + x^9/9! - ... = Sum[0..+inf] (-1^n) * (x^(2*n + 1)) / (2*n + 1)!
// cos(x) = 1 - x^2/2! + x^4/4! - x^6/6! + x^8/8! - ... = Sum[0..+inf] (-1^n) * (x^(2*n)) / (2*n)!
public BigDecimal cos(BigDecimal x)
{
BigDecimal res = new BigDecimal("1.0");
BigDecimal xn = x.multiply(x);
for (int i = 0; i < _trigFactors.size(); i++)
{
BigDecimal factor = (BigDecimal) _trigFactors.get(i);
factor = factor.multiply(xn);
if (i % 2 == 0)
{
factor = factor.negate();
}
res = res.add(factor);
xn = xn.multiply(x);
xn = xn.multiply(x);
xn = xn.setScale(_precision + _extraPrecision, BigDecimal.ROUND_HALF_UP);
}
return res.setScale(_precision, BigDecimal.ROUND_HALF_UP);
}
public static void main(String[] args)
{
BigDecimalTrigTest bdtt = new BigDecimalTrigTest(50);
BigDecimal half = new BigDecimal("0.5");
System.out.println("Math.cos(0.5) = " + Math.cos(0.5));
System.out.println("this.cos(0.5) = " + bdtt.cos(half));
}
}
:
cos(.5) to 10000 digits
Wolfram Alpha对body {
/* Set the Serial counter to 0 */
counter-reset: Serial;
}
table {
border-collapse: separate;
}
tr td:first-child:before {
/* Increment the Serial counter */
counter-increment: Serial;
/* Display the counter */
content: "Serial is: " counter(Serial);
}
的测试(如@RC所评论的)给出了与我的测试代码相同精度的相同结果。也许5 足以作为额外的精确度。但我需要更多的测试才能确定。
答案 0 :(得分:0)
您可以将-pi&gt; x&gt; = pi中的数字减少到该范围。随着abs(x)的增加,sin(x)的泰勒展开变得不那么准确,因此将x减小到这个范围会增加你对大数的准确性。