¿Cuáles son las mejores bibliotecas matemáticas de precisión arbitraria multiplataforma (portátiles)? [cerrado]

81

Estoy buscando una buena biblioteca matemática de precisión arbitraria en C o C ++. ¿Podría darme algunos consejos o sugerencias?

Los requisitos principales:

  1. Se debe manejar arbitrariamente grandes números enteros, mi interés principal está en números enteros. En caso de que no sepa qué significa la palabra arbitrariamente grande, ¡imagine algo como 100000! (el factorial de 100000).

  2. No es necesario especificar la precisión durante la inicialización de la biblioteca o la creación del objeto. La precisión solo debe estar limitada por los recursos disponibles del sistema.

  3. Se debe utilizar todo el poder de la plataforma, y debe manejar números “pequeñas” de forma nativa. Eso significa que en una plataforma de 64 bits, el cálculo (2 ^ 33 + 2 ^ 32) debería utilizar las instrucciones de CPU de 64 bits disponibles. La biblioteca no debería calcular esto de la misma manera que lo hace con (2 ^ 66 + 2 ^ 65) en la misma plataforma.

  4. Se debe manejar de manera eficiente adición ( +), resta ( -), multiplicación ( *), la división de enteros ( /), el resto ( %), de potencia ( **), incremento ( ++), decremento ( --), GCD, factorial, y otra común número entero cálculos aritméticos. La capacidad de manejar funciones como la raíz cuadrada y el logaritmo que no producen resultados enteros es una ventaja. La capacidad de manejar cálculos simbólicos es aún mejor.

Esto es lo que encontré hasta ahora:

  1. Java 's BigInteger y BigDecimal clase: He estado usando estos hasta el momento. He leído el código fuente, pero no entiendo las matemáticas subyacentes. Puede estar basado en teorías y algoritmos que nunca aprendí.

  2. El tipo de entero integrado o en las bibliotecas centrales de bc , Python , Ruby , Haskell , Lisp , Erlang , OCaml , PHP , algunos otros lenguajes: he usado algunos de estos, pero no tengo idea de qué biblioteca están usando, o qué tipo de implementación están usando.

Lo que ya he sabido:

  1. Use charpara dígitos decimales y char*para cadenas decimales, y realice cálculos en los dígitos usando un forbucle.

  2. Usar int(o long int, o long long) como una "unidad" básica y una matriz de ese tipo como un entero largo arbitrario, y hacer cálculos sobre los elementos usando un for-loop.

  3. Usar un tipo de entero para almacenar un dígito decimal (o algunos dígitos) como BCD (decimal codificado en binario) .

  4. Algoritmo de multiplicación de Booth .

Lo que no se:

  1. Imprimir la matriz binaria mencionada anteriormente en decimal sin utilizar métodos ingenuos. Un ejemplo de un método ingenuo: (1) sume los bits del más bajo al más alto: 1, 2, 4, 8, 16, 32,… (2) use una char*-string mencionada anteriormente para almacenar los resultados decimales intermedios).

Lo que aprecio:

  1. Buenas comparaciones en GMP , MPFR , decNumber (u otras bibliotecas que son buenas en su opinión).

  2. Buenas sugerencias sobre libros y artículos que debería leer. Por ejemplo, una ilustración con cifras sobre cómo funciona un algoritmo de conversión de binario a decimal no ingenuo sería bueno. El artículo " Conversión binaria a decimal con precisión limitada " de Douglas W. Jones es un ejemplo de un buen artículo.

  3. Cualquier ayuda en general.

Por favor, no responder a esta pregunta si usted piensa que el uso double(o long double, u long long double) puede resolver este problema fácilmente. Si cree que sí, no comprende el problema en cuestión.

Siu Ching Pong -Asuka Kenji-
fuente
3
Por lo que puedo ver, GMP parece ser una buena biblioteca. Lo que me pregunto es por qué es necesario que los contribuyentes de Python / Haskell / Erlang / etc. reinventen la rueda. Si GMP es tan bueno, ¿por qué no confiar en él? La licencia GPL / LGPL puede ser uno de los problemas, pero a pesar de esto (y también del problema del modo de redondeo), ¿existen otras desventajas de GMP? ¿Es el entero integrado de Python / Haskell / Erlang / cualquier biblioteca de criptografía más rápido que GMP? Si es así, me gustaría extraerlo y usarlo, si la licencia lo permite.
Siu Ching Pong -Asuka Kenji-
Encontré un buen artículo en cs.uiowa.edu/~jones/bcd/decimal.html por Douglas W. Jones. El artículo describe un método para convertir un entero de 16 bits en una representación decimal utilizando solo aritmética de números enteros de 8 bits. La idea es dividir el número de 16 bits en 4 nibbles, cada uno de los cuales representa un "dígito" de base 16. Entonces, dígito-0 (n0) representa x1, n1 => x16, n2 => x256, n3 => x4096. Entonces, es obvio que el dígito 0 del número decimal (d0) es el dígito 0 del resultado de n0 * 1 + n1 * 6 + n2 * 6 + n3 * 6. Al manejar correctamente el acarreo, d1 a d4 pueden también se calculará.
Siu Ching Pong -Asuka Kenji-
Sin embargo, por lo que podía imaginar, la idea de Douglas anterior no podía extenderse para manejar enteros binarios arbitrariamente largos. Esto se debe a que los números 1 (16 ^ 0), 16 (16 ^ 1), 256 (16 ^ 2) y 4096 (16 ^ 3) están precalculados. El problema entonces es cómo representar 16 ^ n en decimal para n arbitrariamente grande.
Siu Ching Pong -Asuka Kenji-

Respuestas:

24

GMP es la opción popular. Squeak Smalltalk tiene una biblioteca muy agradable, pero está escrito en Smalltalk.

Solicitó libros o artículos relevantes. La parte complicada de los bignums es la división larga. Recomiendo el artículo de Per Brinch Hansen, Multiple-Length Division Revisited: A Tour of the Minefield .

Norman Ramsey
fuente
¡Gracias por su enlace al periódico! Sí, estoy de acuerdo en que la división es la parte más complicada. Sabía cómo hacer la división a mano usando "métodos de papel y lápiz" hace mucho tiempo :-), y por lo tanto, el mismo método se puede aplicar a una cadena decimal de char *(cada uno charrepresenta un dígito decimal) o una int *cadena BCD ( cada uno intrepresenta 4/8/16 dígitos BCD). Sin embargo, me pregunto si las bibliotecas de nivel de producción del mundo real imitan el "método de papel y lápiz", ya que es demasiado lento.
Siu Ching Pong -Asuka Kenji-
Para ver por qué, imaginemos cómo funciona 100,000,000,000,000,000 / 333,333,333,333: El primer paso es comparar 100,000,000,000con 333,333,333,333. Debido a que el primero es menor que el segundo, el cálculo simplemente pasa al siguiente dígito. El segundo paso es encontrar el cociente de 1,000,000,000,000 / 333,333,333,333, esto implica una multiplicación de prueba y error de 333,333,333,333 * 1(y * 2, * 3y * 4), o hacer restas sucesivas en un ciclo. ¿Ves lo lento que es? Creo que existen algoritmos más eficientes.
Siu Ching Pong -Asuka Kenji-
3
@Sui: Brinch Hanson muestra cómo se puede reducir el método de prueba y error a dos intentos como máximo. Realmente es muy impresionante.
Norman Ramsey
Bien, déjame echar un vistazo más detallado al artículo. ¡Gracias!
Siu Ching Pong -Asuka Kenji-
1
No estoy seguro de dónde terminó encontrando su solución, ni qué formato usó para almacenar dígitos, pero el formato de nybble COMP-3 de COBOL es mucho más agradable de manejar, ya que es más compacto, cada 4 bits almacena un 0-9 value, Y, no es necesario restar 30 hexadecimales del valor char ASCII para obtener un dígito utilizable.
13

En general, la biblioteca de precisión arbitraria de propósito general más rápida es GMP . Si desea trabajar con valores de punto flotante, consulte la biblioteca MPFR . MPFR se basa en GMP.

Con respecto al soporte nativo de precisión arbitraria en otros lenguajes, Python usa su propia implementación debido a razones de licencia, tamaño del código y portabilidad del código. El módulo GMPY permite a Python acceder a la biblioteca GMP.

casevh
fuente
¡Gracias por su respuesta! Mencionaste "portabilidad de código". ¿Podría explicar cuál es el problema? Pensé que GMP es portátil y es compatible con las principales plataformas ...
Siu Ching Pong -Asuka Kenji-
2
"portabilidad de código" no es lo mismo que "compatible con las principales plataformas". Python usa una implementación simple que hace muy pocas suposiciones sobre el comportamiento del compilador de C, por lo que el mismo código se puede compilar en casi cualquier compilador de C. GMP usa más código (C y ensamblador altamente ajustado) que hace que GMP sea más rápido pero también hace más suposiciones sobre el comportamiento del compilador y ensamblador de C. Por ejemplo, GMP no es compatible con los compiladores de Microsoft Visual Studio. Hay una bifurcación GMP llamada MPIR (www.mpir.org) que es compatible con los compiladores de Microsoft.
casevh
Veo. Eso significa que la implementación de Python es más como ANSI C mientras que la implementación de GMP usa trucos __asm ​​... Gracias por sus explicaciones.
Siu Ching Pong -Asuka Kenji-
8

Consulte TTMath , una pequeña biblioteca con plantilla que solo incluye encabezados y es gratuita para uso personal y comercial.

Andrey Syrokomskiy
fuente
¡Oye! Esta es una biblioteca fácil de usar, y parece que utiliza la potencia de la CPU y usa algo de magia de plantilla C ++ para completar el trabajo. ¡Gran biblioteca! +1 para ti!
Siu Ching Pong -Asuka Kenjii-
Sí, y tiene una licencia BSD permisiva sin copyleft.
plasmacel
De la página anterior: "El tamaño de los valores se establece en el momento de la compilación". - por lo que esto no cumple con los requisitos.
osxdirk
7

No he comparado bibliotecas aritméticas de precisión arbitraria entre sí, pero las personas que sí parecen haberse decidido de manera más o menos uniforme por las GMP. Por lo que vale, los números enteros de precisión arbitraria en GHC Haskell y GNU Guile Scheme se implementan utilizando GMP, y la implementación más rápida del punto de referencia pidigits en el tiroteo de idiomas se basa en GMP.

Richard Barrell
fuente
¡Gracias! ^ ___ ^ ¡Buena información!
Siu Ching Pong -Asuka Kenji-
4

¿Y Pari ? Está construido sobre GMP superior y proporciona todas las demás ventajas sobre las operaciones de teoría de números que necesitará (y muchas cosas de cálculo simbólico).

fortran
fuente
Hola fortran (!), ¡Se ve bien! ¡Gracias por su información!
Siu Ching Pong -Asuka Kenji-
De nada :-) También con Pari puede rodar prototipos rápidos usando GP y cuando esté satisfecho escriba la versión C optimizada (y creo que viene con un compilador GP-> C para ayudar con eso también)
fortran