Подтвердить что ты не робот

Почему Haskell может обрабатывать очень большие числа?

Hugs> 94535^445
1376320882321377050696053887661515621104890164005282153069726424773999801846841903244827702943487982707454966009456016735041878000604143500908532887464920380605164932112687039059526672109818924234920844448231612532570718657160234177285377733830104834041049076609912488237219608445995072867798430614935403219495883835042862802917980856774134757390782052200512932375660858045003581611863121089979673784484701791210379500218604466721285456487387736825167702127154268533859979529612671925052419513844416493584817268143587955662039327860394141299238613042312035808541735213479394437496215520277526351425482512084759462579494878772787079101513841720202004639843443083454387175700954018825292148776647553122504118229978165851660083576570848983047255050145168802863168613110619584686348869690774233051669081248424584219383477237544209892290799448207462345346336076966775224683516220960618177284844330167142846351091001423033864986042919757795382577032341453971393897073354841924116635150129850119992031076354249371062307034564093077675129303383786693131843907104175619570678630497198824622804914508555467550904967368926176118094672479099827962889569753303773699017596074205893197641101210911874606040804983166177455705972192827752532495287749766682029353154226049380290040508900715169403153139668217790502306177709467234413947747673881158973344492079455405942662489751581189327200960698310350121179918845099840977270519116578719881752429190273998774113278822810866144521416958558406602325070095207349450759264393913367193083149679216066539911941983836313340998945139132421885688290888674594474605510238217590823316979504437667252929278291853368754482552573193289277120902144178425726693671235675042499401282016643202758246845332593475338220708351934511933096882598943512036679145593929114103343255708217768511665236173107020739195152050863630870948954052925049746246549772984384435109578859863612603574306739909728739428192798727373799081111333186135697868385292787575475482883660605162944306327057220313320376280182432763977906971557137715710757099478269250731209785404487629107297262798803645379809868663503452656912571816192881412782623078761411808958183665272686617730596943579533808499348879195167683064937591552734375

Почему Haskell вычисляет такое большое число, а другие языки, такие как Java, не могут (так легко)?

4b9b3361

Ответ 1

Java имеет класс BigInteger.

Он мог бы создать это средство на языке, но (как и многие языки) он имеет тенденцию приближать примитивные функции к вещам, поддерживаемым процессором.

Haskell, с другой стороны, подчеркивает выразительность в стиле математических обозначений, где соображения "производительности" в значительной степени несущественны.

Ответ 2

Это разница в философии дизайна:

  • Дизайнеры Haskell хотели быть уверены, что пользователи не будут удивлены, по-видимому, произвольным отказом целочисленного вычисления, которому требуется больше 32 бит.

  • Разработчики Java хотели убедиться, что пользователи не будут удивлены, по-видимому, произвольной деградацией производительности, вызванной большим количеством вычислений над целыми числами, которые должны иметь более 32 бит.

На каждом языке вам нужно сделать что-то особенное, чтобы получить другое целое число.

Есть долгая, почетная история языков, поддерживающих сколь угодно большие целые числа по умолчанию. Два из моих любимых Icon и Smalltalk, которые лет старше 25 лет.

Ответ 3

Числовые литералы в Haskell перегружены так, что они могут представлять несколько конкретных типов (например, Int, Integer, Float или даже MyOwnNumber).

Вы можете вручную выбрать конкретный тип, указав информацию о типе, например:

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

Эти три значения имеют разные типы, и выполняемые операции будут вести себя по-другому.

Точный размер Int зависит от реализации, но может быть чем-то вроде 28 бит, этот тип ведет себя как примитив Java Int, например. он будет переполняться.

An Integer - это тип, который может содержать целые числа произвольной точности, такие как Java BigInteger.

И Float похож на Java Float, используя арифметику с плавающей запятой.

Как и числовые литералы, многие операторы также перегружены (используя классы и могут использоваться для разных типов. Таким образом, оператор + может работать как с Int, так и Float s.

В вашем случае, поскольку вы не указали какую-либо информацию о типе, интерпретатор по умолчанию будет иметь тип Integer. Это означает, что для оператора ^ он также выберет экземпляр Integer. Разрешение вычислений с целыми числами произвольной точности.

Ответ 4

В Java есть понятие "примитивные типы данных" (которые являются типами, поддерживаемыми процессором), и они отличаются от всех других классов.

В Haskell Int - тип, подобный всем другим типам, и поэтому он легко стал членом классов Num и Integral, используемых в (^) ("(^) :: (Num a, Integral b) => a -> b -> a"). Другим членом этих типов выглядит Integer, который поддерживает целые числа всех размеров (если у вас достаточно памяти для их цифр).

В Java вы можете использовать многие библиотеки Big Numbers, но для них не будут использоваться операторы infix, к которым вы привыкли, поскольку они предназначены только для "примитивных типов" на Java.

Ответ 5

Короткий и основной ответ заключается в том, что они реализуют по умолчанию целые числа. В Java стандартный int - 32 бита. Подпись, которая дает вам диапазон от −2,147,483,648 до +2,147,483,647.

Тем не менее, в Java есть bignum классы. Если вы их используете, вы также сможете использовать произвольно большие числа.

Ответ 6

Как уже упоминалось, если вы имеете 32-битные слова и используете полный диапазон, вы получаете -2 ^ 31 до 2 ^ 31-1, используя два дополнения.

Сохраняя несколько бит слова, эти биты могут использоваться для переноса информации типа для значения. То есть значения "знают" свой собственный тип во время выполнения. Остальные биты используются для переноса данных значения.

Целочисленные значения, которые вписываются в эти оставшиеся биты, могут быть сохранены непосредственно в слове. Такие целые числа обычно называются "fixnums". Если они не подходят, то биты типа слова указывают, что это "bigint", а остальные биты используются для хранения указателя памяти в куче, где хранится значение bigint.

Компилятор должен перевести ваши арифметические выражения в несколько путей кода, которые охватывают допустимые комбинации типов для операндов. Пример добавления:

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

Множество оптимизаций в компиляторах для этих языков фокусируется на том, чтобы избежать накладных расходов на проверки типа времени выполнения, необходимые для выполнения этой работы. Часто также есть способы явного указания компилятору, что автоматическое понижение должности от fixnum до bignum нежелательно, и вместо этого требуется переполнение 32-битных целых чисел. Это может быть очень важно для эффективного использования криптографических алгоритмов.

Ответ 7

Это вопрос о том, как кодировать числа. Традиционный способ сделать это - кодировать числа с заданным количеством бит, где вы не можете иметь бесконечную точность. По-видимому, Haskell делает это с переменным количеством бит для числа, которое также является прекрасным, но обычно означает, что все математические вычисления выполняются в программном обеспечении, поскольку аппаратное ускорение, как правило, доступно только для конечной точности.

Ответ 8

Вы можете использовать BigInteger, чтобы сделать то же самое. Haskell - это функциональный язык, более строгий, чем Java.

Одна из причин, по которой у нас так много языков, заключается в том, что разные языки лучше подходят для разных задач, поскольку они были разработаны с различными предположениями. Большинство функциональных языков проще с математическими функциями, но имеют тенденцию бороться с другими вариантами использования, например. haskell вряд ли будет хорошим выбором для написания графического интерфейса.