2009-07-26 13 views
26
Hugs> 94535^445 
1376320882321377050696053887661515621104890164005282153069726424773999801846841903244827702943487982707454966009456016735041878000604143500908532887464920380605164932112687039059526672109818924234920844448231612532570718657160234177285377733830104834041049076609912488237219608445995072867798430614935403219495883835042862802917980856774134757390782052200512932375660858045003581611863121089979673784484701791210379500218604466721285456487387736825167702127154268533859979529612671925052419513844416493584817268143587955662039327860394141299238613042312035808541735213479394437496215520277526351425482512084759462579494878772787079101513841720202004639843443083454387175700954018825292148776647553122504118229978165851660083576570848983047255050145168802863168613110619584686348869690774233051669081248424584219383477237544209892290799448207462345346336076966775224683516220960618177284844330167142846351091001423033864986042919757795382577032341453971393897073354841924116635150129850119992031076354249371062307034564093077675129303383786693131843907104175619570678630497198824622804914508555467550904967368926176118094672479099827962889569753303773699017596074205893197641101210911874606040804983166177455705972192827752532495287749766682029353154226049380290040508900715169403153139668217790502306177709467234413947747673881158973344492079455405942662489751581189327200960698310350121179918845099840977270519116578719881752429190273998774113278822810866144521416958558406602325070095207349450759264393913367193083149679216066539911941983836313340998945139132421885688290888674594474605510238217590823316979504437667252929278291853368754482552573193289277120902144178425726693671235675042499401282016643202758246845332593475338220708351934511933096882598943512036679145593929114103343255708217768511665236173107020739195152050863630870948954052925049746246549772984384435109578859863612603574306739909728739428192798727373799081111333186135697868385292787575475482883660605162944306327057220313320376280182432763977906971557137715710757099478269250731209785404487629107297262798803645379809868663503452656912571816192881412782623078761411808958183665272686617730596943579533808499348879195167683064937591552734375 

¿Por qué Haskell puede calcular un número tan grande y otros idiomas, como Java, no pueden (tan fácilmente)?¿Por qué Haskell maneja números muy grandes fácilmente?

Respuesta

25

Java tiene la clase BigInteger.

Podría haber construido esta facilidad en el idioma, pero (como en muchos idiomas) tiende a hacer que las características primitivas se asocien estrechamente a las cosas que son compatibles con la CPU.

Haskell, por otro lado, enfatiza la expresividad en el estilo de la notación matemática, donde las consideraciones de "rendimiento" son en gran medida irrelevantes.

+20

Para que quede claro, los desarrolladores de Haskell en general no consideran que las consideraciones de rendimiento sean irrelevantes. – amindfv

+0

Estoy de acuerdo - Pongo citas sobre "rendimiento" porque apoyo el enfoque de Haskell. –

+1

En el código Haskell de la vida real, se usa Int. Integer solo se usa cuando también se usa BigInteger en Java. Por lo tanto, en realidad no existe una diferencia práctica, excepto que en Haskell, Integer es el tipo predeterminado si no especifica un tipo. (Dado que se supone [correctamente] que no es código de producción de todos modos si no se especifican tipos). – Evi1M4chine

3

La respuesta breve y básica es que implementan enteros predeterminados diferentes. En Java, un int estándar es de 32 bits. Firmado, eso le da un rango de −2,147,483,648 a +2,147,483,647.

Dicho esto, Java también tiene bignum clases. Si los usa, también obtendrá la capacidad de utilizar números arbitrariamente grandes.

0

Es una cuestión de cómo codificar números. La forma tradicional de hacerlo es codificar números con un número dado de bits, donde no se puede tener una precisión infinita. Al parecer, Haskell hace esto con una cantidad variable de bits para un número que también es bueno, pero generalmente significa que todas las matemáticas se han hecho en software, ya que la aceleración de hardware generalmente solo está disponible para precisión finita.

+1

Prefiero adivinar que Haskell proporciona verificación de rango suave y conversión de números, al igual que Lisp. Siempre que sus números se mantengan dentro del rango fijado, los cálculos se realizan normalmente y directamente en la máquina, pero el desbordamiento se detecta y se elimina mediante la conversión a bignum. – Svante

+1

@Svante: no, eso no es completamente cierto. Haskell no tiene conversiones automáticas entre ningún tipo ni tiene verificación de rango de Ints. es completamente un problema de tipos ambiguos. en Haskell, los literales enteros se pueden escribir a cualquier tipo que instale Num. aquí el tipo es ambiguo. de forma predeterminada, Haskell se predetermina a Integer, como se explica aquí: http://www.haskell.org/onlinereport/decls.html#default-decls – newacct

+1

@newacct: Si bien el Informe Haskell define la forma en que se comportan los enteros, eso no significa no pueden implementarse como fixnums y bignums. Si hay una implementación de Haskell que realmente hace esto, no lo sé. –

0

Puede usar BigInteger para hacer lo mismo. Haskell es un lenguaje funcional que es más escueto que Java.

Una razón por la que tenemos tantos idiomas es que los diferentes idiomas son mejores en tareas diferentes, ya que fueron diseñados con diferentes suposiciones. La mayoría de los lenguajes funcionales son más simples con funciones matemáticas, pero tienden a tener problemas con otros casos de uso, p. No es probable que Haskell sea una buena opción para escribir una GUI.

+1

con ghcjs ¡ahora es una gran elección! – Fresheyeball

6

Java tiene la noción de "tipos de datos primitivos" (que son los tipos que admite el procesador) y esos son diferentes de todas las demás clases.

En Haskell, Int es un tipo como todos los otros tipos, y por lo tanto se hizo fácilmente un miembro de las Num y Integral clases de tipos utilizados en (^) ("(^) :: (Num a, Integral b) => a -> b -> a"). Otro miembro de esas clases de tipos es Integer, que admite enteros de todos los tamaños (siempre que tenga suficiente memoria para sus dígitos).

En Java, puede usar muchas bibliotecas de "Big Numbers", pero las operaciones para ellas no usarán los operadores de infijo a los que está acostumbrado, porque esos son solo para "Tipos primitivos" en Java.

+1

Ver si entiendo esto correctamente. Entonces, ¿el operador^en Haskell no está directamente vinculado a un tipo específico, sino a una "categoría" (o dos de tales categorías, al parecer) de tipos que en cierto sentido se comportan de la misma manera? ¿Haskell luego elige qué tipo dar una expresión en tiempo de ejecución, pero siempre dentro de la misma categoría? Como en el ejemplo del póster, el resultado de 94535^445 necesita un tipo de Entero para ser representado, pero el resultado de 3^5 puede hacerlo con un Int para ser representado. – harms

+4

@harms: Haskell escribe inferencia y revisa el tipo en tiempo de compilación. En este caso, dado que no se proporciona información de tipo, se establecerá de manera predeterminada en 'Integer' (que es como un' BigNumber 'de Java). Sin embargo, puede agregar manualmente información de tipo para decir que los números son 'Int' (como Java primitive' int'), en ese caso el resultado de la operación '^' simplemente se desbordará y producirá un resultado 'Int' incorrecto. –

1

Como ya se mencionó, si tiene palabras de 32 bits y utiliza el rango completo obtiene -2^31 a 2^31-1 con el complemento de dos.

Al reservar algunos bits de la palabra, esos bits se pueden usar para transportar información de tipo para el valor. Es decir, los valores "conocen" su propio tipo en tiempo de ejecución. Los bits restantes se utilizan para transportar los datos del valor.

Los valores enteros que se ajustan a estos bits restantes se pueden almacenar directamente en la palabra. Dichos enteros generalmente se llaman 'fixnums'. Si no encajan, los bits de tipo de la palabra indican que es un 'bigint', y los bits restantes se usan para almacenar un puntero de memoria en el montón donde se almacena el valor bigint.

El compilador necesita traducir sus expresiones aritméticas en varias rutas de código que cubren las combinaciones de tipos permitidas para los operandos. Ejemplo para la adición:

  • fixnum + fixnum
  • bigint + fixnum
  • fixnum + bigint
  • bigint + bigint

Una gran cantidad de optimizaciones en los compiladores de estos idiomas se centran en evitar la sobrecarga para los controles de tipo de tiempo de ejecución necesarios para hacer que esto funcione. A menudo también hay maneras de decirle explícitamente al compilador que la degradación automática de fixnum a bignum no es deseada, y en cambio uno quiere el comportamiento de desbordamiento de enteros de 32 bits. Esto puede ser muy importante para implementar algoritmos de criptografía de manera eficiente.

+0

no hay necesariamente una sobrecarga en el tiempo de ejecución con polimorfismo, y toma Haskell como ejemplo para eso. Además, no veo cómo la parte entera de los bits reservados es relevante para esta pregunta, ya que no creo que ni Java ni Haskell lo usen. – yairchu

+0

Es cierto que no hay sobrecarga de tiempo de ejecución si puede optimizarse. Haskell (al menos GHC) realiza promoción automática de fixnums a bigintegers en overflow (para el tipo Integer). Que java no solo explica por qué el primitivo int o el entero se desbordan, requiriendo el uso de bigint y asumiendo los costos incluso si el valor se ajusta al rango fijo. – Christian

10

literales numéricos en Haskell están sobrecargados de modo que puedan representar múltiples tipos concretos (como Int, Integer, Float o incluso MyOwnNumber).

Se puede elegir manualmente un tipo específico al proporcionar información de tipo, así:

x = 4 :: Int 
y = 4 :: Integer 
z = 4 :: Float 

Estos tres valores tienen diferentes tipos y operaciones realizadas en éstos se comportarán de forma diferente.

El tamaño exacto de Int depende de la implementación, pero puede ser algo así como 28 bits, este tipo se comporta como una primitiva Java int, p. Ej. se desbordará

Un Integer es un tipo que puede contener enteros de precisión arbitraria, como Java BigInteger.

Y una Float es como una Java float, utilizando la aritmética de punto flotante.

Al igual que los literales numéricos, muchos operadores también están sobrecargados (usando type classes), y por lo tanto se pueden usar con los diferentes tipos. Por lo tanto, el operador + puede trabajar tanto con Int sy Float s.

En su caso, dado que no proporcionó ningún tipo de información, el intérprete utilizará de manera predeterminada el tipo Integer. Esto significa que para el operador ^, también elegirá la instancia Integer. Permitir cálculos enteros de precisión arbitraria.

42

Es una diferencia en la filosofía de diseño:

  • Los diseñadores de Haskell querían estar seguros de que los usuarios no estarían sorprendidos por el fracaso aparentemente arbitraria de un cálculo entero necesitan más de 32 bits.

  • Los diseñadores de Java querían asegurarse de que los usuarios no se sorprenderían por la degradación del rendimiento aparentemente arbitraria causada por hacer muchos cálculos sobre enteros que necesitan más de 32 bits.

En cada idioma, debe hacer algo especial para obtener el otro tipo de número entero.

Hay una larga y honorable historia de idiomas que admiten enteros arbitrariamente grandes por defecto. Dos de mis favoritos son Icon y Smalltalk, que tienen más de 25 años.

+10

Aunque "algo especial" en Haskell es un poco más fácil: solo significa usar, por ejemplo, "Int32" como tipo, mientras que en Java, tengo entendido que la falta de sobrecarga del operador te obligará a decir cosas como 'x .add (y) 'o' x.multiply (y) ' –

+2

Common Lisp ftw: D –

+0

Sí, creo que" algo especial "es muy injusto para Haskell. Puede usar un int acotado en Haskell con la misma cantidad de código que un int acotado en Java. 'int x = 5' vs' x = 5 :: Int'. – semicolon

Cuestiones relacionadas