本文整理汇总了C#中BigDecimal.Ulp方法的典型用法代码示例。如果您正苦于以下问题:C# BigDecimal.Ulp方法的具体用法?C# BigDecimal.Ulp怎么用?C# BigDecimal.Ulp使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类BigDecimal
的用法示例。
在下文中一共展示了BigDecimal.Ulp方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: Hypot
public static BigDecimal Hypot(int n, BigDecimal x)
{
/* compute n^2+x^2 in infinite precision
*/
BigDecimal z = (new BigDecimal(n)).Pow(2).Add(x.Pow(2));
/* Truncate to the precision set by x. Absolute error = in z (square of the result) is |2*x*xerr|,
* where the error is 1/2 of the ulp. Two intermediate protection digits.
* zerr is a signed value, but used only in conjunction with err2prec(), so this feature does not harm.
*/
double zerr = x.ToDouble()*x.Ulp().ToDouble();
var mc = new MathContext(2 + ErrorToPrecision(z.ToDouble(), zerr));
/* Pull square root */
z = Sqrt(z.Round(mc));
/* Final rounding. Absolute error in the square root is x*xerr/z, where zerr holds 2*x*xerr.
*/
mc = new MathContext(ErrorToPrecision(z.ToDouble(), 0.5*zerr/z.ToDouble()));
return z.Round(mc);
}
示例2: Log
public static BigDecimal Log(BigDecimal x)
{
/* the value is undefined if x is negative.
*/
if (x.CompareTo(BigDecimal.Zero) < 0)
throw new ArithmeticException("Cannot take log of negative " + x);
if (x.CompareTo(BigDecimal.One) == 0) {
/* log 1. = 0. */
return ScalePrecision(BigDecimal.Zero, x.Precision - 1);
}
if (System.Math.Abs(x.ToDouble() - 1.0) <= 0.3) {
/* The standard Taylor series around x=1, z=0, z=x-1. Abramowitz-Stegun 4.124.
* The absolute error is err(z)/(1+z) = err(x)/x.
*/
BigDecimal z = ScalePrecision(x.Subtract(BigDecimal.One), 2);
BigDecimal zpown = z;
double eps = 0.5*x.Ulp().ToDouble()/System.Math.Abs(x.ToDouble());
BigDecimal resul = z;
for (int k = 2;; k++) {
zpown = MultiplyRound(zpown, z);
BigDecimal c = DivideRound(zpown, k);
if (k%2 == 0)
resul = resul.Subtract(c);
else
resul = resul.Add(c);
if (System.Math.Abs(c.ToDouble()) < eps)
break;
}
var mc = new MathContext(ErrorToPrecision(resul.ToDouble(), eps));
return resul.Round(mc);
} else {
double xDbl = x.ToDouble();
double xUlpDbl = x.Ulp().ToDouble();
/* Map log(x) = log root[r](x)^r = r*log( root[r](x)) with the aim
* to move roor[r](x) near to 1.2 (that is, below the 0.3 appearing above), where log(1.2) is roughly 0.2.
*/
var r = (int) (System.Math.Log(xDbl)/0.2);
/* Since the actual requirement is a function of the value 0.3 appearing above,
* we avoid the hypothetical case of endless recurrence by ensuring that r >= 2.
*/
r = System.Math.Max(2, r);
/* Compute r-th root with 2 additional digits of precision
*/
BigDecimal xhighpr = ScalePrecision(x, 2);
BigDecimal resul = Root(r, xhighpr);
resul = Log(resul).Multiply(new BigDecimal(r));
/* error propagation: log(x+errx) = log(x)+errx/x, so the absolute error
* in the result equals the relative error in the input, xUlpDbl/xDbl .
*/
var mc = new MathContext(ErrorToPrecision(resul.ToDouble(), xUlpDbl/xDbl));
return resul.Round(mc);
}
}
示例3: Exp
public static BigDecimal Exp(BigDecimal x)
{
/* To calculate the value if x is negative, use exp(-x) = 1/exp(x)
*/
if (x.CompareTo(BigDecimal.Zero) < 0) {
BigDecimal invx = Exp(x.Negate());
/* Relative error in inverse of invx is the same as the relative errror in invx.
* This is used to define the precision of the result.
*/
var mc = new MathContext(invx.Precision);
return BigDecimal.One.Divide(invx, mc);
}
if (x.CompareTo(BigDecimal.Zero) == 0) {
/* recover the valid number of digits from x.ulp(), if x hits the
* zero. The x.precision() is 1 then, and does not provide this information.
*/
return ScalePrecision(BigDecimal.One, -(int) (System.Math.Log10(x.Ulp().ToDouble())));
}
/* Push the number in the Taylor expansion down to a small
* value where TAYLOR_NTERM terms will do. If x<1, the n-th term is of the order
* x^n/n!, and equal to both the absolute and relative error of the result
* since the result is close to 1. The x.ulp() sets the relative and absolute error
* of the result, as estimated from the first Taylor term.
* We want x^TAYLOR_NTERM/TAYLOR_NTERM! < x.ulp, which is guaranteed if
* x^TAYLOR_NTERM < TAYLOR_NTERM*(TAYLOR_NTERM-1)*...*x.ulp.
*/
double xDbl = x.ToDouble();
double xUlpDbl = x.Ulp().ToDouble();
if (System.Math.Pow(xDbl, TaylorNterm) < TaylorNterm*(TaylorNterm - 1.0)*(TaylorNterm - 2.0)*xUlpDbl) {
/* Add TAYLOR_NTERM terms of the Taylor expansion (Euler's sum formula)
*/
BigDecimal resul = BigDecimal.One;
/* x^i */
BigDecimal xpowi = BigDecimal.One;
/* i factorial */
BigInteger ifac = BigInteger.One;
/* TAYLOR_NTERM terms to be added means we move x.ulp() to the right
* for each power of 10 in TAYLOR_NTERM, so the addition won't add noise beyond
* what's already in x.
*/
var mcTay = new MathContext(ErrorToPrecision(1d, xUlpDbl/TaylorNterm));
for (int i = 1; i <= TaylorNterm; i++) {
ifac = ifac.Multiply(BigInteger.ValueOf(i));
xpowi = xpowi.Multiply(x);
BigDecimal c = xpowi.Divide(new BigDecimal(ifac), mcTay);
resul = resul.Add(c);
if (System.Math.Abs(xpowi.ToDouble()) < i &&
System.Math.Abs(c.ToDouble()) < 0.5*xUlpDbl)
break;
}
/* exp(x+deltax) = exp(x)(1+deltax) if deltax is <<1. So the relative error
* in the result equals the absolute error in the argument.
*/
var mc = new MathContext(ErrorToPrecision(xUlpDbl/2d));
return resul.Round(mc);
} else {
/* Compute exp(x) = (exp(0.1*x))^10. Division by 10 does not lead
* to loss of accuracy.
*/
var exSc = (int) (1.0 - System.Math.Log10(TaylorNterm*(TaylorNterm - 1.0)*(TaylorNterm - 2.0)*xUlpDbl
/System.Math.Pow(xDbl, TaylorNterm))/(TaylorNterm - 1.0));
BigDecimal xby10 = x.ScaleByPowerOfTen(-exSc);
BigDecimal expxby10 = Exp(xby10);
/* Final powering by 10 means that the relative error of the result
* is 10 times the relative error of the base (First order binomial expansion).
* This looses one digit.
*/
var mc = new MathContext(expxby10.Precision - exSc);
/* Rescaling the powers of 10 is done in chunks of a maximum of 8 to avoid an invalid operation
* response by the BigDecimal.pow library or integer overflow.
*/
while (exSc > 0) {
int exsub = System.Math.Min(8, exSc);
exSc -= exsub;
var mctmp = new MathContext(expxby10.Precision - exsub + 2);
int pex = 1;
while (exsub-- > 0)
pex *= 10;
expxby10 = expxby10.Pow(pex, mctmp);
}
return expxby10.Round(mc);
}
}
示例4: Cos
public static BigDecimal Cos(BigDecimal x)
{
if (x.CompareTo(BigDecimal.Zero) < 0)
return Cos(x.Negate());
if (x.CompareTo(BigDecimal.Zero) == 0)
return BigDecimal.One;
/* reduce modulo 2pi
*/
BigDecimal res = Mod2Pi(x);
double errpi = 0.5*System.Math.Abs(x.Ulp().ToDouble());
var mc = new MathContext(2 + ErrorToPrecision(3.14159, errpi));
BigDecimal p = PiRound(mc);
mc = new MathContext(x.Precision);
if (res.CompareTo(p) > 0) {
/* pi<x<=2pi: cos(x)= - cos(x-pi)
*/
return Cos(SubtractRound(res, p)).Negate();
}
if (res.Multiply(BigDecimal.ValueOf(2)).CompareTo(p) > 0) {
/* pi/2<x<=pi: cos(x)= -cos(pi-x)
*/
return Cos(SubtractRound(p, res)).Negate();
}
/* for the range 0<=x<Pi/2 one could use cos(2x)= 1-2*sin^2(x)
* to split this further, or use the cos up to pi/4 and the sine higher up.
throw new ProviderException("Not implemented: cosine ") ;
*/
if (res.Multiply(BigDecimal.ValueOf(4)).CompareTo(p) > 0) {
/* x>pi/4: cos(x) = sin(pi/2-x)
*/
return Sin(SubtractRound(p.Divide(BigDecimal.ValueOf(2)), res));
}
/* Simple Taylor expansion, sum_{i=0..infinity} (-1)^(..)res^(2i)/(2i)! */
BigDecimal resul = BigDecimal.One;
/* x^i */
BigDecimal xpowi = BigDecimal.One;
/* 2i factorial */
BigInteger ifac = BigInteger.One;
/* The absolute error in the result is the error in x^2/2 which is x times the error in x.
*/
double xUlpDbl = 0.5*res.Ulp().ToDouble()*res.ToDouble();
/* The error in the result is set by the error in x^2/2 itself, xUlpDbl.
* We need at most k terms to push x^(2k+1)/(2k+1)! below this value.
* x^(2k) < xUlpDbl; (2k)*log(x) < log(xUlpDbl);
*/
int k = (int) (System.Math.Log(xUlpDbl)/System.Math.Log(res.ToDouble()))/2;
var mcTay = new MathContext(ErrorToPrecision(1d, xUlpDbl/k));
for (int i = 1;; i++) {
/* TBD: at which precision will 2*i-1 or 2*i overflow?
*/
ifac = ifac.Multiply(BigInteger.ValueOf((2*i - 1)));
ifac = ifac.Multiply(BigInteger.ValueOf((2*i)));
xpowi = xpowi.Multiply(res).Multiply(res).Negate();
BigDecimal corr = xpowi.Divide(new BigDecimal(ifac), mcTay);
resul = resul.Add(corr);
if (corr.Abs().ToDouble() < 0.5*xUlpDbl)
break;
}
/* The error in the result is governed by the error in x itself.
*/
mc = new MathContext(ErrorToPrecision(resul.ToDouble(), xUlpDbl));
return resul.Round(mc);
}
示例5: Cot
public static BigDecimal Cot(BigDecimal x)
{
if (x.CompareTo(BigDecimal.Zero) == 0) {
throw new ArithmeticException("Cannot take cot of zero " + x);
}
if (x.CompareTo(BigDecimal.Zero) < 0) {
return Cot(x.Negate()).Negate();
}
/* reduce modulo pi
*/
BigDecimal res = ModPi(x);
/* absolute error in the result is err(x)/sin^2(x) to lowest order
*/
double xDbl = res.ToDouble();
double xUlpDbl = x.Ulp().ToDouble()/2d;
double eps = xUlpDbl/2d/System.Math.Pow(System.Math.Sin(xDbl), 2d);
BigDecimal xhighpr = ScalePrecision(res, 2);
BigDecimal xhighprSq = MultiplyRound(xhighpr, xhighpr);
var mc = new MathContext(ErrorToPrecision(xhighpr.ToDouble(), eps));
BigDecimal resul = BigDecimal.One.Divide(xhighpr, mc);
/* x^(2i-1) */
BigDecimal xpowi = xhighpr;
var b = new Bernoulli();
/* 2^(2i) */
var fourn = BigInteger.Parse("4");
/* (2i)! */
BigInteger fac = BigInteger.One;
for (int i = 1;; i++) {
Rational f = b[2*i];
fac = fac.Multiply(BigInteger.ValueOf((2*i))).Multiply(BigInteger.ValueOf((2*i - 1)));
f = f.Multiply(fourn).Divide(fac);
BigDecimal c = MultiplyRound(xpowi, f);
if (i%2 == 0)
resul = resul.Add(c);
else
resul = resul.Subtract(c);
if (System.Math.Abs(c.ToDouble()) < 0.1*eps)
break;
fourn = fourn.ShiftLeft(2);
xpowi = MultiplyRound(xpowi, xhighprSq);
}
mc = new MathContext(ErrorToPrecision(resul.ToDouble(), eps));
return resul.Round(mc);
}
示例6: Tan
public static BigDecimal Tan(BigDecimal x)
{
if (x.CompareTo(BigDecimal.Zero) == 0)
return BigDecimal.Zero;
if (x.CompareTo(BigDecimal.Zero) < 0) {
return Tan(x.Negate()).Negate();
}
/* reduce modulo pi
*/
BigDecimal res = ModPi(x);
/* absolute error in the result is err(x)/cos^2(x) to lowest order
*/
double xDbl = res.ToDouble();
double xUlpDbl = x.Ulp().ToDouble()/2d;
double eps = xUlpDbl/2d/System.Math.Pow(System.Math.Cos(xDbl), 2d);
if (xDbl > 0.8) {
/* tan(x) = 1/cot(x) */
BigDecimal co = Cot(x);
var mc = new MathContext(ErrorToPrecision(1d/co.ToDouble(), eps));
return BigDecimal.One.Divide(co, mc);
} else {
BigDecimal xhighpr = ScalePrecision(res, 2);
BigDecimal xhighprSq = MultiplyRound(xhighpr, xhighpr);
BigDecimal resul = xhighpr.Plus();
/* x^(2i+1) */
BigDecimal xpowi = xhighpr;
var b = new Bernoulli();
/* 2^(2i) */
BigInteger fourn = BigInteger.ValueOf(4);
/* (2i)! */
BigInteger fac = BigInteger.ValueOf(2);
for (int i = 2;; i++) {
Rational f = b[2*i].Abs();
fourn = fourn.ShiftLeft(2);
fac = fac.Multiply(BigInteger.ValueOf((2*i))).Multiply(BigInteger.ValueOf((2*i - 1)));
f = f.Multiply(fourn).Multiply(fourn.Subtract(BigInteger.One)).Divide(fac);
xpowi = MultiplyRound(xpowi, xhighprSq);
BigDecimal c = MultiplyRound(xpowi, f);
resul = resul.Add(c);
if (System.Math.Abs(c.ToDouble()) < 0.1*eps)
break;
}
var mc = new MathContext(ErrorToPrecision(resul.ToDouble(), eps));
return resul.Round(mc);
}
}
示例7: UlpZero
public void UlpZero()
{
String a = "0";
int aScale = 2;
BigDecimal aNumber = new BigDecimal(BigInteger.Parse(a), aScale);
BigDecimal result = aNumber.Ulp();
String res = "0.01";
int resScale = 2;
Assert.AreEqual(res, result.ToString(), "incorrect value");
Assert.AreEqual(resScale, result.Scale, "incorrect scale");
}
示例8: Sin
public static BigDecimal Sin(BigDecimal x)
{
if (x.CompareTo(BigDecimal.Zero) < 0)
return Sin(x.Negate()).Negate();
if (x.CompareTo(BigDecimal.Zero) == 0)
return BigDecimal.Zero;
/* reduce modulo 2pi
*/
BigDecimal res = Mod2Pi(x);
double errpi = 0.5*System.Math.Abs(x.Ulp().ToDouble());
var mc = new MathContext(2 + ErrorToPrecision(3.14159, errpi));
BigDecimal p = PiRound(mc);
mc = new MathContext(x.Precision);
if (res.CompareTo(p) > 0) {
/* pi<x<=2pi: sin(x)= - sin(x-pi)
*/
return Sin(SubtractRound(res, p)).Negate();
}
if (res.Multiply(BigDecimal.ValueOf(2)).CompareTo(p) > 0) {
/* pi/2<x<=pi: sin(x)= sin(pi-x)
*/
return Sin(SubtractRound(p, res));
}
/* for the range 0<=x<Pi/2 one could use sin(2x)=2sin(x)cos(x)
* to split this further. Here, use the sine up to pi/4 and the cosine higher up.
*/
if (res.Multiply(BigDecimal.ValueOf(4)).CompareTo(p) > 0) {
/* x>pi/4: sin(x) = cos(pi/2-x)
*/
return Cos(SubtractRound(p.Divide(BigDecimal.ValueOf(2)), res));
}
/* Simple Taylor expansion, sum_{i=1..infinity} (-1)^(..)res^(2i+1)/(2i+1)! */
BigDecimal resul = res;
/* x^i */
BigDecimal xpowi = res;
/* 2i+1 factorial */
BigInteger ifac = BigInteger.One;
/* The error in the result is set by the error in x itself.
*/
double xUlpDbl = res.Ulp().ToDouble();
/* The error in the result is set by the error in x itself.
* We need at most k terms to squeeze x^(2k+1)/(2k+1)! below this value.
* x^(2k+1) < x.ulp; (2k+1)*log10(x) < -x.precision; 2k*log10(x)< -x.precision;
* 2k*(-log10(x)) > x.precision; 2k*log10(1/x) > x.precision
*/
int k = (int) (res.Precision/System.Math.Log10(1.0/res.ToDouble()))/2;
var mcTay = new MathContext(ErrorToPrecision(res.ToDouble(), xUlpDbl/k));
for (int i = 1;; i++) {
/* TBD: at which precision will 2*i or 2*i+1 overflow?
*/
ifac = ifac.Multiply(BigInteger.ValueOf(2*i));
ifac = ifac.Multiply(BigInteger.ValueOf((2*i + 1)));
xpowi = xpowi.Multiply(res).Multiply(res).Negate();
BigDecimal corr = xpowi.Divide(new BigDecimal(ifac), mcTay);
resul = resul.Add(corr);
if (corr.Abs().ToDouble() < 0.5*xUlpDbl)
break;
}
/* The error in the result is set by the error in x itself.
*/
mc = new MathContext(res.Precision);
return resul.Round(mc);
}
示例9: SubtractRound
public static BigDecimal SubtractRound(BigDecimal x, BigDecimal y)
{
BigDecimal resul = x.Subtract(y);
// The estimation of the absolute error in the result is |err(y)|+|err(x)|
double errR = System.Math.Abs(y.Ulp().ToDouble()/2d) + System.Math.Abs(x.Ulp().ToDouble()/2d);
var mc = new MathContext(ErrorToPrecision(resul.ToDouble(), errR));
return resul.Round(mc);
}
示例10: Root
public static BigDecimal Root(int n, BigDecimal x)
{
if (x.CompareTo(BigDecimal.Zero) < 0)
throw new ArithmeticException("negative argument " + x + " of root");
if (n <= 0)
throw new ArithmeticException("negative power " + n + " of root");
if (n == 1)
return x;
/* start the computation from a double precision estimate */
var s = new BigDecimal(System.Math.Pow(x.ToDouble(), 1.0/n));
/* this creates nth with nominal precision of 1 digit
*/
var nth = new BigDecimal(n);
/* Specify an internal accuracy within the loop which is
* slightly larger than what is demanded by 'eps' below.
*/
BigDecimal xhighpr = ScalePrecision(x, 2);
var mc = new MathContext(2 + x.Precision);
/* Relative accuracy of the result is eps.
*/
double eps = x.Ulp().ToDouble()/(2*n*x.ToDouble());
for (;;) {
/* s = s -(s/n-x/n/s^(n-1)) = s-(s-x/s^(n-1))/n; test correction s/n-x/s for being
* smaller than the precision requested. The relative correction is (1-x/s^n)/n,
*/
BigDecimal c = xhighpr.Divide(s.Pow(n - 1), mc);
c = s.Subtract(c);
var locmc = new MathContext(c.Precision);
c = c.Divide(nth, locmc);
s = s.Subtract(c);
if (System.Math.Abs(c.ToDouble()/s.ToDouble()) < eps)
break;
}
return s.Round(new MathContext(ErrorToPrecision(eps)));
}
示例11: PowRound
public static BigDecimal PowRound(BigDecimal x, Rational q)
{
/** Special cases: x^1=x and x^0 = 1
*/
if (q.CompareTo(BigInteger.One) == 0)
return x;
if (q.Sign == 0)
return BigDecimal.One;
if (q.IsInteger) {
/* We are sure that the denominator is positive here, because normalize() has been
* called during constrution etc.
*/
return PowRound(x, q.Numerator);
}
/* Refuse to operate on the general negative basis. The integer q have already been handled above.
*/
if (x.CompareTo(BigDecimal.Zero) < 0)
throw new ArithmeticException("Cannot power negative " + x);
if (q.IsIntegerFraction) {
/* Newton method with first estimate in double precision.
* The disadvantage of this first line here is that the result must fit in the
* standard range of double precision numbers exponents.
*/
double estim = System.Math.Pow(x.ToDouble(), q.ToDouble());
var res = new BigDecimal(estim);
/* The error in x^q is q*x^(q-1)*Delta(x).
* The relative error is q*Delta(x)/x, q times the relative error of x.
*/
var reserr = new BigDecimal(0.5*q.Abs().ToDouble()
*x.Ulp().Divide(x.Abs(), MathContext.Decimal64).ToDouble());
/* The main point in branching the cases above is that this conversion
* will succeed for numerator and denominator of q.
*/
int qa = q.Numerator.ToInt32();
int qb = q.Denominator.ToInt32();
/* Newton iterations. */
BigDecimal xpowa = PowRound(x, qa);
for (;;) {
/* numerator and denominator of the Newton term. The major
* disadvantage of this implementation is that the updates of the powers
* of the new estimate are done in full precision calling BigDecimal.pow(),
* which becomes slow if the denominator of q is large.
*/
BigDecimal nu = res.Pow(qb).Subtract(xpowa);
BigDecimal de = MultiplyRound(res.Pow(qb - 1), q.Denominator);
/* estimated correction */
BigDecimal eps = nu.Divide(de, MathContext.Decimal64);
BigDecimal err = res.Multiply(reserr, MathContext.Decimal64);
int precDiv = 2 + ErrorToPrecision(eps, err);
if (precDiv <= 0) {
/* The case when the precision is already reached and any precision
* will do. */
eps = nu.Divide(de, MathContext.Decimal32);
} else {
eps = nu.Divide(de, new MathContext(precDiv));
}
res = SubtractRound(res, eps);
/* reached final precision if the relative error fell below reserr,
* |eps/res| < reserr
*/
if (eps.Divide(res, MathContext.Decimal64).Abs().CompareTo(reserr) < 0) {
/* delete the bits of extra precision kept in this
* working copy.
*/
return res.Round(new MathContext(ErrorToPrecision(reserr.ToDouble())));
}
}
}
/* The error in x^q is q*x^(q-1)*Delta(x) + Delta(q)*x^q*log(x).
* The relative error is q/x*Delta(x) + Delta(q)*log(x). Convert q to a floating point
* number such that its relative error becomes negligible: Delta(q)/q << Delta(x)/x/log(x) .
*/
int precq = 3 + ErrorToPrecision((x.Ulp().Divide(x, MathContext.Decimal64)).ToDouble()
/System.Math.Log(x.ToDouble()));
/* Perform the actual calculation as exponentiation of two floating point numbers.
*/
return Pow(x, q.ToBigDecimal(new MathContext(precq)));
}
示例12: Pow
public static BigDecimal Pow(BigDecimal x, BigDecimal y)
{
if (x.CompareTo(BigDecimal.Zero) < 0)
throw new ArithmeticException("Cannot power negative " + x);
if (x.CompareTo(BigDecimal.Zero) == 0)
return BigDecimal.Zero;
/* return x^y = exp(y*log(x)) ;
*/
BigDecimal logx = Log(x);
BigDecimal ylogx = y.Multiply(logx);
BigDecimal resul = Exp(ylogx);
/* The estimation of the relative error in the result is |log(x)*err(y)|+|y*err(x)/x|
*/
double errR = System.Math.Abs(logx.ToDouble())*y.Ulp().ToDouble()/2d
+ System.Math.Abs(y.ToDouble()*x.Ulp().ToDouble()/2d/x.ToDouble());
var mcR = new MathContext(ErrorToPrecision(1.0, errR));
return resul.Round(mcR);
}
示例13: Mod2Pi
public static BigDecimal Mod2Pi(BigDecimal x)
{
/* write x= 2*pi*k+r with the precision in r defined by the precision of x and not
* compromised by the precision of 2*pi, so the ulp of 2*pi*k should match the ulp of x.
* First get a guess of k to figure out how many digits of 2*pi are needed.
*/
var k = (int) (0.5*x.ToDouble()/System.Math.PI);
/* want to have err(2*pi*k)< err(x)=0.5*x.ulp, so err(pi) = err(x)/(4k) with two safety digits
*/
double err2pi;
if (k != 0)
err2pi = 0.25*System.Math.Abs(x.Ulp().ToDouble()/k);
else
err2pi = 0.5*System.Math.Abs(x.Ulp().ToDouble());
var mc = new MathContext(2 + ErrorToPrecision(6.283, err2pi));
BigDecimal twopi = PiRound(mc).Multiply(new BigDecimal(2));
/* Delegate the actual operation to the BigDecimal class, which may return
* a negative value of x was negative .
*/
BigDecimal res = x.Remainder(twopi);
if (res.CompareTo(BigDecimal.Zero) < 0)
res = res.Add(twopi);
/* The actual precision is set by the input value, its absolute value of x.ulp()/2.
*/
mc = new MathContext(ErrorToPrecision(res.ToDouble(), x.Ulp().ToDouble()/2d));
return res.Round(mc);
}
示例14: Asin
public static BigDecimal Asin(BigDecimal x)
{
if (x.CompareTo(BigDecimal.One) > 0 ||
x.CompareTo(BigDecimal.One.Negate()) < 0) {
throw new ArithmeticException("Out of range argument " + x + " of asin");
}
if (x.CompareTo(BigDecimal.Zero) == 0)
return BigDecimal.Zero;
if (x.CompareTo(BigDecimal.One) == 0) {
/* arcsin(1) = pi/2
*/
double errpi = System.Math.Sqrt(x.Ulp().ToDouble());
var mc = new MathContext(ErrorToPrecision(3.14159, errpi));
return PiRound(mc).Divide(new BigDecimal(2));
}
if (x.CompareTo(BigDecimal.Zero) < 0) {
return Asin(x.Negate()).Negate();
}
if (x.ToDouble() > 0.7) {
BigDecimal xCompl = BigDecimal.One.Subtract(x);
double xDbl = x.ToDouble();
double xUlpDbl = x.Ulp().ToDouble()/2d;
double eps = xUlpDbl/2d/System.Math.Sqrt(1d - System.Math.Pow(xDbl, 2d));
BigDecimal xhighpr = ScalePrecision(xCompl, 3);
BigDecimal xhighprV = DivideRound(xhighpr, 4);
BigDecimal resul = BigDecimal.One;
/* x^(2i+1) */
BigDecimal xpowi = BigDecimal.One;
/* i factorial */
BigInteger ifacN = BigInteger.One;
BigInteger ifacD = BigInteger.One;
for (int i = 1;; i++) {
ifacN = ifacN.Multiply(BigInteger.ValueOf((2*i - 1)));
ifacD = ifacD.Multiply(BigInteger.ValueOf(i));
if (i == 1)
xpowi = xhighprV;
else
xpowi = MultiplyRound(xpowi, xhighprV);
BigDecimal c = DivideRound(MultiplyRound(xpowi, ifacN),
ifacD.Multiply(BigInteger.ValueOf((2*i + 1))));
resul = resul.Add(c);
/* series started 1+x/12+... which yields an estimate of the sum's error
*/
if (System.Math.Abs(c.ToDouble()) < xUlpDbl/120d)
break;
}
/* sqrt(2*z)*(1+...)
*/
xpowi = Sqrt(xhighpr.Multiply(new BigDecimal(2)));
resul = MultiplyRound(xpowi, resul);
var mc = new MathContext(resul.Precision);
BigDecimal pihalf = PiRound(mc).Divide(new BigDecimal(2));
mc = new MathContext(ErrorToPrecision(resul.ToDouble(), eps));
return pihalf.Subtract(resul, mc);
} else {
/* absolute error in the result is err(x)/sqrt(1-x^2) to lowest order
*/
double xDbl = x.ToDouble();
double xUlpDbl = x.Ulp().ToDouble()/2d;
double eps = xUlpDbl/2d/System.Math.Sqrt(1d - System.Math.Pow(xDbl, 2d));
BigDecimal xhighpr = ScalePrecision(x, 2);
BigDecimal xhighprSq = MultiplyRound(xhighpr, xhighpr);
BigDecimal resul = xhighpr.Plus();
/* x^(2i+1) */
BigDecimal xpowi = xhighpr;
/* i factorial */
BigInteger ifacN = BigInteger.One;
BigInteger ifacD = BigInteger.One;
for (int i = 1;; i++) {
ifacN = ifacN.Multiply(BigInteger.ValueOf((2*i - 1)));
ifacD = ifacD.Multiply(BigInteger.ValueOf((2*i)));
xpowi = MultiplyRound(xpowi, xhighprSq);
BigDecimal c = DivideRound(MultiplyRound(xpowi, ifacN),
ifacD.Multiply(BigInteger.ValueOf((2*i + 1))));
resul = resul.Add(c);
if (System.Math.Abs(c.ToDouble()) < 0.1*eps)
break;
}
var mc = new MathContext(ErrorToPrecision(resul.ToDouble(), eps));
return resul.Round(mc);
}
}
示例15: ModPi
public static BigDecimal ModPi(BigDecimal x)
{
/* write x= pi*k+r with the precision in r defined by the precision of x and not
* compromised by the precision of pi, so the ulp of pi*k should match the ulp of x.
* First get a guess of k to figure out how many digits of pi are needed.
*/
var k = (int) (x.ToDouble()/System.Math.PI);
/* want to have err(pi*k)< err(x)=x.ulp/2, so err(pi) = err(x)/(2k) with two safety digits
*/
double errpi;
if (k != 0)
errpi = 0.5*System.Math.Abs(x.Ulp().ToDouble()/k);
else
errpi = 0.5*System.Math.Abs(x.Ulp().ToDouble());
var mc = new MathContext(2 + ErrorToPrecision(3.1416, errpi));
BigDecimal onepi = PiRound(mc);
BigDecimal pihalf = onepi.Divide(new BigDecimal(2));
/* Delegate the actual operation to the BigDecimal class, which may return
* a negative value of x was negative .
*/
BigDecimal res = x.Remainder(onepi);
if (res.CompareTo(pihalf) > 0)
res = res.Subtract(onepi);
else if (res.CompareTo(pihalf.Negate()) < 0)
res = res.Add(onepi);
/* The actual precision is set by the input value, its absolute value of x.ulp()/2.
*/
mc = new MathContext(ErrorToPrecision(res.ToDouble(), x.Ulp().ToDouble()/2d));
return res.Round(mc);
}