probableprime metodos library isprobableprime java math biginteger logarithm

java - metodos - isprobableprime biginteger



Logaritmo para BigInteger (5)

¿Qué tan preciso necesitas que sea? Si solo necesitas 15 dígitos de precisión puedes hacerlo.

BigInteger bi = double log = Math.log(bi.doubleValue());

Esto funcionaría para valores de hasta 1023 bits. Después de eso el valor ya no cabría en un doble.

Tengo un número de BigInteger , por ejemplo, más allá del 2 64 . Ahora quiero calcular el logaritmo de ese número de BigInteger , pero el método BigInteger.log() no existe. ¿Cómo calculo el logaritmo (natural) de mi valor grande de BigInteger ?


Conviértelo en un BigDecimal mentir esto:

new BigDecimal(val); // where val is a BigInteger

y registro de BigDecimalUtils de BigDecimalUtils en él: D


Recibí ayuda de google pero aparentemente no necesita aplicar el registro a sus grandes números de BigInteger directamente, ya que se puede desglosar de la siguiente manera:

928 = 1000 * 0.928 lg 928 = lg 1000 * lg 0.928 = 3 + lg 0.928

Por lo tanto, su problema se reduce al cálculo / aproximación de logaritmos que permiten una precisión arbitraria creciente, tal vez math.stackexchange.com?


Si desea admitir enteros arbitrariamente grandes, no es seguro hacerlo

Math.log(bigInteger.doubleValue());

porque esto fallaría si el argumento supera el double rango (aproximadamente 2 ^ 1024 o 10 ^ 308, es decir, más de 300 dígitos decimales).

Aquí está mi propia clase que proporciona los métodos.

double logBigInteger(BigInteger val); double logBigDecimal(BigDecimal val); BigDecimal expBig(double exponent); BigDecimal powBig(double a, double b);

Funcionan de manera segura incluso cuando BigDecimal / BigInteger son demasiado grandes (o demasiado pequeños) para poder representarse como tipo double .

/** * Provides some mathematical operations on BigDecimal and BigInteger */ public class BigMath { protected static final double LOG2 = Math.log(2.0); protected static final double LOG10 = Math.log(10.0); // numbers greater than 10^MAX_DIGITS_10 or e^MAX_DIGITS_EXP are considered unsafe (''too big'') for floating point operations protected static final int MAX_DIGITS_EXP = 677; protected static final int MAX_DIGITS_10 = 294; // ~ MAX_DIGITS_EXP/LN(10) protected static final int MAX_DIGITS_2 = 977; // ~ MAX_DIGITS_EXP/LN(2) /** * Computes the natural logarithm of a BigInteger. * * Works for really big integers (practically unlimited), even when the argument * falls outside the <tt>double</tt> range * * Returns Nan if argument is negative, NEGATIVE_INFINITY if zero. * * @param val Argument * @return Natural logarithm, as in <tt>Math.log()</tt> */ public static double logBigInteger(BigInteger val) { if (val.signum() < 1) return val.signum() < 0 ? Double.NaN : Double.NEGATIVE_INFINITY; int blex = val.bitLength() - MAX_DIGITS_2; // any value in 60..1023 works ok here if (blex > 0) val = val.shiftRight(blex); double res = Math.log(val.doubleValue()); return blex > 0 ? res + blex * LOG2 : res; } /** * Computes the natural logarithm of a BigDecimal. * * Works for really big (or really small) arguments, even outside the double range. * * Returns Nan if argument is negative, NEGATIVE_INFINITY if zero. * * @param val Argument * @return Natural logarithm, as in <tt>Math.log()</tt> */ public static double logBigDecimal(BigDecimal val) { if (val.signum() < 1) return val.signum() < 0 ? Double.NaN : Double.NEGATIVE_INFINITY; int digits = val.precision() - val.scale(); if (digits < MAX_DIGITS_10 && digits > -MAX_DIGITS_10) return Math.log(val.doubleValue()); else return logBigInteger(val.unscaledValue()) - val.scale() * LOG10; } /** * Computes the exponential function, returning a BigDecimal (precision ~ 16). * * Works for very big and very small exponents, even when the result * falls outside the double range * * @param exponent Any finite value (infinite or Nan throws IllegalArgumentException) * @return The value of e (base of the natural logarithms) raised to the given exponent, as in <tt>Math.exp()</tt> */ public static BigDecimal expBig(double exponent) { if (!Double.isFinite(exponent)) throw new IllegalArgumentException("Infinite not accepted: " + exponent); // e^b = e^(b2+c) = e^b2 2^t with e^c = 2^t double bc = MAX_DIGITS_EXP; if (exponent < bc && exponent > -bc) return new BigDecimal(Math.exp(exponent), MathContext.DECIMAL64); boolean neg = false; if (exponent < 0) { neg = true; exponent = -exponent; } double b2 = bc; double c = exponent - bc; int t = (int) Math.ceil(c / LOG10); c = t * LOG10; b2 = exponent - c; if (neg) { b2 = -b2; t = -t; } return new BigDecimal(Math.exp(b2), MathContext.DECIMAL64).movePointRight(t); } /** * Same as Math.pow(a,b) but returns a BigDecimal (precision ~ 16). * * Works even for outputs that fall outside the <tt>double</tt> range * * The only limit is that b * log(a) does not overflow the double range * * @param a Base. Should be non-negative * @param b Exponent. Should be finite (and non-negative if base is zero) * @return Returns the value of the first argument raised to the power of the second argument. */ public static BigDecimal powBig(double a, double b) { if (!(Double.isFinite(a) && Double.isFinite(b))) throw new IllegalArgumentException(Double.isFinite(b) ? "base not finite: a=" + a : "exponent not finite: b=" + b); if (b == 0) return BigDecimal.ONE; if (b == 1) return BigDecimal.valueOf(a); if (a == 0) { if (b >= 0) return BigDecimal.ZERO; else throw new IllegalArgumentException("0**negative = infinite"); } if (a < 0) { throw new IllegalArgumentException("negative base a=" + a); } double x = b * Math.log(a); if (Math.abs(x) < MAX_DIGITS_EXP) return BigDecimal.valueOf(Math.pow(a, b)); else return expBig(x); } }


Si puede usar Google Guava y solo requiere un registro de base 2 o base 10, puede usar los métodos de la clase BigIntegerMath de Guava.