多倍長ライブラリ(更新中)
計算が遅かったり多少の誤差があるのも仕様です。
package jp.wshounen;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
public class BigMath {
public static int precision = 20;
public static MathContext context = new MathContext(24,
RoundingMode.HALF_EVEN);
private static BigDecimal ATAN0D1 = null;
private static BigDecimal ATAN1 = null;
private static BigDecimal LOG1D1 = null;
private static BigDecimal LOG2 = null;
public static BigDecimal PI = pi();
public static BigDecimal E = e();
public static BigDecimal round(final BigDecimal in, final int precision) {
return in.round(new MathContext(precision, RoundingMode.HALF_EVEN));
}
public static BigDecimal round(final BigDecimal in) {
return in.setScale(0, RoundingMode.HALF_EVEN);
}
public static BigDecimal degToRad(final BigDecimal arcsec) {
return arcsec.multiply(ATAN1).divide(new BigDecimal(45), context);
}
public static BigDecimal radToDeg(final BigDecimal rad) {
return rad.multiply(new BigDecimal(45)).divide(ATAN1, context);
}
public static BigDecimal floor(final BigDecimal in) {
return in.setScale(0, RoundingMode.FLOOR);
}
public static BigDecimal ceil(final BigDecimal in) {
return in.setScale(0, RoundingMode.CEILING);
}
private static BigDecimal pi() {
ATAN0D1 = atan0d1();
ATAN1 = atan(BigDecimal.ONE);
return shift(ATAN1, 2);
}
private static BigDecimal e() {
LOG1D1 = log1d1();
LOG2 = log(new BigDecimal(2));
System.out.println(BigMath.LOG1D1);
System.out.println(BigMath.LOG2);
return exp(BigDecimal.ONE);
}
public static void setPrecision(final int prec) {
if (prec >= 20 && prec != precision) {
precision = prec;
setContext((int) Math.ceil(Math.log10(prec) * 3) + prec,
RoundingMode.HALF_EVEN);
}
}
public static void setContext(final int prec, final RoundingMode mode) {
if (prec > precision && prec != context.getPrecision()) {
context = new MathContext(prec, mode);
if (ATAN0D1.precision() < prec) {
LOG1D1 = null;
LOG2 = null;
ATAN0D1 = null;
ATAN1 = null;
E = e();
PI = pi();
}
}
}
public static BigDecimal shift(final BigDecimal in, final int index) {
if (index == 0) {
return in;
}
BigInteger bi1 = in.unscaledValue();
int num = in.scale();
if (index > 0) {
return new BigDecimal(bi1.shiftLeft(index), num);
}
BigInteger bi2 = bi1.shiftLeft(index);
bi1 = bi2.shiftRight(index).negate().add(bi1);
return (bi1.signum() == 0) ? new BigDecimal(bi2, num) : new BigDecimal(
BigInteger.valueOf(5).pow(-index).multiply(bi1), num - index)
.stripTrailingZeros().add(new BigDecimal(bi2, num));
}
public static BigDecimal shift(final BigDecimal in, final int index,
final MathContext context) {
return shift(in, index).plus(context);
}
public static BigDecimal asin(final BigDecimal in) {
int num = in.abs().compareTo(BigDecimal.ONE);
if (num == 0) {
return (in.signum() > 0) ? shift(ATAN1, 1) : shift(ATAN1, 1)
.negate();
} else if (num == -1) {
return (in.signum() == 0) ? BigDecimal.ZERO : shift(atan(in.divide(
sqrt(in.pow(2).negate().add(BigDecimal.ONE)).add(
BigDecimal.ONE), context)), 1);
} else if (round(in.abs(), precision).compareTo(BigDecimal.ONE) == 0) {
return (in.signum() > 0) ? shift(ATAN1, 1) : shift(ATAN1, 1)
.negate();
} else {
return null;
}
}
public static BigDecimal acos(final BigDecimal in) {
int num = in.abs().compareTo(BigDecimal.ONE);
if (num == 0) {
return (in.signum() > 0) ? BigDecimal.ZERO : shift(ATAN1, 2);
} else if (num == -1) {
return (in.signum() == 0) ? shift(ATAN1, 1)
: shift(atan(
in.divide(
sqrt(in.pow(2).negate().add(BigDecimal.ONE))
.add(BigDecimal.ONE), context))
.negate().add(ATAN1), 1);
} else if (round(in.abs(), precision).compareTo(BigDecimal.ONE) == 0) {
return (in.signum() > 0) ? BigDecimal.ZERO : shift(ATAN1, 2);
} else {
return null;
}
}
private static BigDecimal atan0d1() {
if (ATAN0D1 != null) {
return ATAN0D1.plus();
}
BigDecimal bd = BigDecimal.ONE;
BigDecimal[] temp = new BigDecimal[] { BigDecimal.ONE
.scaleByPowerOfTen(-1) };
BigDecimal coef = temp[0].plus();
do {
bd = new BigDecimal(2).add(bd);
coef = coef.scaleByPowerOfTen(-2).negate();
temp = new BigDecimal[] {
temp[0].multiply(bd).add(coef).divide(bd, context), temp[0] };
} while (temp[0].compareTo(temp[1]) != 0);
return temp[0];
}
public static BigDecimal atan(final BigDecimal in) {
BigDecimal perten = BigDecimal.ONE.scaleByPowerOfTen(-1);
BigDecimal bd1, bd2, coef;
BigDecimal[] temp;
int num = in.signum();
bd1 = in.abs(context);
bd2 = BigDecimal.ZERO;
if (num == 0) {
return BigDecimal.ZERO;
} else if (bd1.compareTo(perten) == 0) {
return (num > 0) ? ATAN0D1.plus() : ATAN0D1.negate();
} else if (bd1.compareTo(BigDecimal.ONE) == 0 && num == 1
&& ATAN1 != null) {
return ATAN1.plus();
} else if (bd1.compareTo(BigDecimal.ONE) == 1) {
bd1 = new BigDecimal(-1).add(bd1).divide(bd1.add(BigDecimal.ONE),
context);
bd2 = bd2.add(ATAN1);
}
perten = perten.negate();
while (bd1.signum() == 1) {
bd1 = perten.add(bd1).divide(
bd1.scaleByPowerOfTen(-1).add(BigDecimal.ONE), context);
bd2 = bd2.add(ATAN0D1);
}
if (num == -1) {
bd1 = bd1.negate();
bd2 = bd2.negate();
}
coef = bd1.plus();
temp = new BigDecimal[] { coef.add(bd2, context) };
bd2 = BigDecimal.ONE;
bd1 = bd1.pow(2, context).negate();
do {
bd2 = new BigDecimal(2).add(bd2);
coef = coef.multiply(bd1, context);
temp = new BigDecimal[] {
temp[0].multiply(bd2).add(coef).divide(bd2, context),
temp[0] };
} while (temp[0].compareTo(temp[1]) != 0);
return temp[0];
}
public static BigDecimal root(final BigDecimal in, final int index) {
BigDecimal bd = in.round(context);
int num = bd.signum();
if (num == 0) {
return BigDecimal.ZERO;
} else if (num == -1 || index <= 0) {
return null;
} else if (bd.compareTo(BigDecimal.ONE) == 0 || index == 1) {
return bd;
}
int i = index;
while (i % 2 == 0) {
i /= 2;
bd = sqrt(bd);
}
if (i > 2) {
bd = pow(bd, BigDecimal.ONE.divide(new BigDecimal(i), context));
}
return bd;
}
public static BigDecimal sqrt(final BigDecimal in) {
BigDecimal bd = in.round(context);
int num = bd.signum();
if (num == 0) {
return BigDecimal.ZERO;
} else if (num == -1) {
return null;
} else if (bd.compareTo(BigDecimal.ONE) == 0) {
return bd;
}
BigDecimal[] temp = new BigDecimal[] { bd };
do {
temp = new BigDecimal[] {
temp[0].pow(2).add(bd).divide(shift(temp[0], 1), context),
temp[0] };
} while (temp[0].compareTo(temp[1]) != 0);
return temp[0];
}
private static BigDecimal log1d1() {
if (LOG1D1 != null) {
return LOG1D1.plus();
}
BigDecimal bd = BigDecimal.ONE;
BigDecimal[] temp = new BigDecimal[] { BigDecimal.ONE
.scaleByPowerOfTen(-1) };
BigDecimal coef = temp[0].plus();
do {
bd = BigDecimal.ONE.add(bd);
coef = coef.negate().scaleByPowerOfTen(-1);
temp = new BigDecimal[] {
temp[0].multiply(bd).add(coef).divide(bd, context), temp[0] };
} while (temp[0].compareTo(temp[1]) != 0);
return temp[0];
}
public static BigDecimal log(BigDecimal in) {
if (in.signum() < 1) {
return null;
}
BigDecimal nperten = new BigDecimal(11).scaleByPowerOfTen(-1);
BigDecimal bd1 = in.round(context);
int num = bd1.compareTo(BigDecimal.ONE);
BigDecimal coef, bd2;
if (num == 0) {
return BigDecimal.ZERO;
} else if (num == -1) {
coef = BigDecimal.ONE;
} else {
bd1 = BigDecimal.ONE.divide(bd1, context);
coef = new BigDecimal(-1);
}
bd2 = BigDecimal.ZERO;
nperten = new BigDecimal(5).scaleByPowerOfTen(-1);
while (bd1.compareTo(nperten) == -1) {
bd1 = shift(bd1, 1);
bd2 = bd2.add(LOG2);
}
if (bd1.plus(context).compareTo(nperten) == 0 && LOG2 != null) {
return (num > 0) ? bd2.add(LOG2) : bd2.add(LOG2).negate();
}
nperten = new BigDecimal(11).scaleByPowerOfTen(-1);
while (bd1.compareTo(BigDecimal.ONE) == -1) {
bd1 = bd1.multiply(nperten);
bd2 = bd2.add(LOG1D1);
}
if (num == -1) {
bd2 = bd2.negate();
}
if (bd1.plus(context).compareTo(BigDecimal.ONE) == 0) {
return bd2;
}
bd1 = sqrt(sqrt(bd1));
coef = shift(coef, 2);
bd1 = BigDecimal.ONE.add(new BigDecimal(-1).divide(bd1, context));
coef = coef.multiply(bd1, context);
BigDecimal[] temp = new BigDecimal[] { coef.add(bd2, context) };
bd2 = BigDecimal.ONE;
do {
bd2 = BigDecimal.ONE.add(bd2);
coef = coef.multiply(bd1, context);
temp = new BigDecimal[] {
temp[0].multiply(bd2).add(coef).divide(bd2, context),
temp[0] };
} while (temp[0].compareTo(temp[1]) != 0);
return temp[0];
}
public static BigDecimal sin(final BigDecimal in) {
BigDecimal bd1, bd2;
bd2 = shift(ATAN1, 2);
bd1 = in.remainder(shift(bd2, 1));
int num = bd1.signum();
if (num == 0) {
return BigDecimal.ZERO;
} else if (num < 0) {
return sin(bd1.negate()).negate();
}
if (bd1.compareTo(bd2) > -1) {
return sin(bd1.add(bd2)).negate();
} else if (bd1.compareTo(ATAN1) > 0) {
if (bd1.compareTo(shift(ATAN1, 1)) > 0) {
return sin(bd1.negate().add(bd2));
} else {
return cos(bd1.negate().add(shift(ATAN1, 1)));
}
}
bd1 = shift(bd1, 1).scaleByPowerOfTen(-1);
BigDecimal[] temp = new BigDecimal[] { bd1.plus(context) };
BigDecimal coef = temp[0].plus();
bd1 = bd1.pow(2, context);
bd2 = BigDecimal.ZERO;
do {
bd2 = new BigDecimal(2).add(bd2);
coef = coef.multiply(bd1).divide(
bd2.add(BigDecimal.ONE).multiply(bd2).negate(), context);
temp = new BigDecimal[] { temp[0].add(coef, context), temp[0] };
} while (temp[0].compareTo(temp[1]) != 0);
bd1 = shift(temp[0], 1).pow(2, context);
return bd1.add(new BigDecimal(-5)).multiply(bd1).add(new BigDecimal(5))
.multiply(temp[0], context);
}
public static BigDecimal cos(final BigDecimal in) {
BigDecimal bd1, bd2;
bd2 = shift(ATAN1, 2);
bd1 = in.remainder(shift(bd2, 1));
int num = bd1.signum();
if (num == 0) {
return BigDecimal.ONE;
} else if (num < 0) {
return cos(bd1.negate());
}
if (bd1.compareTo(bd2) > -1) {
return cos(bd1.add(bd2)).negate();
} else if (bd1.compareTo(ATAN1) > -1) {
if (bd1.compareTo(shift(ATAN1, 1)) > 0) {
return cos(bd1.negate().add(bd2)).negate();
} else {
return sin(bd1.negate().add(shift(ATAN1, 1)));
}
}
bd1 = shift(bd1, 1).pow(2, context).scaleByPowerOfTen(-2);
BigDecimal[] temp = new BigDecimal[] { BigDecimal.ONE };
BigDecimal coef = temp[0].plus();
bd2 = BigDecimal.ZERO;
do {
bd2 = new BigDecimal(2).add(bd2);
coef = coef.multiply(bd1).divide(
bd2.negate().add(BigDecimal.ONE).multiply(bd2), context);
temp = new BigDecimal[] { temp[0].add(coef, context), temp[0] };
} while (temp[0].compareTo(temp[1]) != 0);
bd1 = shift(temp[0], 1).pow(2, context);
return bd1.add(new BigDecimal(-5)).multiply(bd1).add(new BigDecimal(5))
.multiply(temp[0], context);
}
public static BigDecimal tan(final BigDecimal in) {
BigDecimal bd = cos(in);
return (bd.signum() == 0) ? null : sin(in).divide(bd, context);
}
public static BigDecimal exp(final BigDecimal in) {
int num = in.signum();
BigDecimal coef = BigDecimal.ONE;
BigDecimal bi;
if (num == 0) {
return BigDecimal.ONE;
} else if (num == 1) {
bi = in.negate(context);
if (bi.compareTo(LOG1D1.negate()) == 0) {
return new BigDecimal(11).scaleByPowerOfTen(-1);
} else if (bi.compareTo(LOG2.negate()) == 0) {
return new BigDecimal(2);
}
} else {
bi = in.plus(context);
if (bi.compareTo(LOG1D1.negate()) == 0) {
return BigDecimal.ONE.divide(new BigDecimal(11), context)
.scaleByPowerOfTen(1);
} else if (bi.compareTo(LOG2.negate()) == 0) {
return new BigDecimal(5).scaleByPowerOfTen(-1);
}
}
if (bi.compareTo(new BigDecimal(-1)) != 0) {
while (bi.signum() == -1) {
bi = bi.add(BigDecimal.ONE);
coef = coef.multiply(E, context);
}
}
if (num == 1) {
bi = bi.negate();
} else {
coef = BigDecimal.ONE.divide(coef, context);
}
BigDecimal[] temp = new BigDecimal[] { coef.round(context) };
num = 0;
do {
num++;
coef = coef.multiply(bi).divide(new BigDecimal(num), context);
temp = new BigDecimal[] { temp[0].add(coef, context), temp[0] };
} while (temp[0].compareTo(temp[1]) != 0);
return temp[0];
}
public static BigDecimal pow(final BigDecimal in, final BigDecimal index) {
BigDecimal bi = log(in);
if (bi == null) {
return null;
} else {
return exp(bi.multiply(index));
}
}
/**
* Matrix of rotation Z to Y. R1(rad).
*/
public static BigDecimal[][] rotX(final BigDecimal rad) {
BigDecimal Cos = cos(rad);
BigDecimal Sin = sin(rad);
return new BigDecimal[][] {
{ BigDecimal.ONE, BigDecimal.ZERO, BigDecimal.ZERO },
{ BigDecimal.ZERO, Cos, Sin.negate() },
{ BigDecimal.ZERO, Sin, Cos } };
}
/**
* Matrix of rotation X to Z. R2(rad).
*/
public static BigDecimal[][] rotY(final BigDecimal rad) {
BigDecimal Cos = cos(rad);
BigDecimal Sin = sin(rad);
return new BigDecimal[][] { { Cos, BigDecimal.ZERO, Sin },
{ BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.ZERO },
{ Sin.negate(), BigDecimal.ZERO, Cos } };
}
/**
* Matrix of rotation Y to X. R3(rad).
*/
public static BigDecimal[][] rotZ(final BigDecimal rad) {
BigDecimal Cos = cos(rad);
BigDecimal Sin = sin(rad);
return new BigDecimal[][] { { Cos, Sin.negate(), BigDecimal.ZERO },
{ Sin, Cos, BigDecimal.ZERO },
{ BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ONE } };
}
/**
* Matrix of rotation Y to X. R(rad).
*/
public static BigDecimal[][] rot2(final BigDecimal rad) {
BigDecimal Cos = cos(rad);
BigDecimal Sin = sin(rad);
return new BigDecimal[][] { { Cos, Sin.negate() }, { Sin, Cos } };
}
/**
* Rotation (1,0,0) to A[0] = (x,y,z). Rotation (0,1,0) to A[1] = (x,y,z).
* Rotation (0,0,1) to A[2] = (x,y,z). Ar = rotA(A,r).
*/
public static BigDecimal[] rotA(final BigDecimal[][] A,
final BigDecimal[] star) {
if (star.length != A.length) {
return null;
} else {
for (int i = 1; i < A.length; i++) {
if (A[i].length != A[0].length) {
return null;
}
}
}
BigDecimal[] res = new BigDecimal[A[0].length];
for (int i = 0; i < A[0].length; i++) {
res[i] = BigDecimal.ZERO;
for (int j = 0; j < star.length; j++) {
res[i] = res[i].add(star[j].multiply(A[j][i]));
}
}
return res;
}
/**
* AB = (rotA(A,B[0]),rotA(A,B[1]),rotA(A,B[2])).
*/
public static BigDecimal[][] rotAB(final BigDecimal[][] A,
final BigDecimal[][] B) {
BigDecimal[][] res = new BigDecimal[B.length][];
for (int i = 0; i < B.length; i++) {
res[i] = rotA(A, B[i]);
}
return res;
}
}
| 固定リンク






最近のコメント