Как избежать "переполнения целочисленного значения ArithmeticException" в Clojure? - PullRequest
17 голосов
/ 07 января 2012

Кажется, это происходит постоянно. Например:

(apply * (range 1 101))

дает мне ошибку

ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow (Numbers.java:1374)

В Ruby 1.9.2 (концептуально) эквивалентный код,

(1..100).reduce(:*)

дает желаемый результат

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

Очевидно, что эти два языка совершенно разные под капотом, но кажется, что они оба должны быть в состоянии справиться с этим вычислением без проблем. Я что-то здесь не так делаю? Или у меня неверное понимание?

Ответы [ 6 ]

37 голосов
/ 07 января 2012

Вам нужно использовать какую-то форму BigInteger.

Попробуйте (apply *' (range 1 101)).

(см. http://dev.clojure.org/display/doc/Documentation+for+1.3+Numerics - очевидно, это автоматически повышается при переполнении?)

6 голосов
/ 04 октября 2014

Начиная с Clojure 1.3, вы должны явным образом приводить Integer (или Long) к BigInt, в противном случае при слишком большом числе будет ошибка «ArithmeticException integer overflow».

Существует три решения, выберитеодна из тех, что вам нравятся:

  • используйте одну из автоматически продвигаемых математических функций: +', -', *', /', inc', dec'

    пример: (apply *' (range 1 101))

  • использовать функцию приведения типа BigInt

    пример: (apply * (range (bigint 1) 101))

  • изменить на числовой литерал BigInt

    пример: (apply * (range 1N 101))

Ссылка: Документация для Clojure 1.3 Числа

6 голосов
/ 07 января 2012

В Ruby есть автоматически продвигаемые вычисления, которые изменяются на большее число типов битов, когда результат переполняет его тип.Из соображений производительности вычисления из Clojure 1.3 и выше не будут автоматически продвигаться, и вам необходимо учитывать, может ли вычисление переполниться, или использовать одну из автоматически продвигаемых математических функций (+', -', *', /'), если производительность не будет проблемой.

1 голос
/ 11 июня 2014

Наткнулся на ту же ситуацию. Для меня использование "1.0" вместо "1" сделало свое дело.

(apply * (range 1.0 1000))

Как документально подтверждено , между числами с плавающей запятой и десятичными существует разница.

0 голосов
/ 07 января 2012

в 1.3.0

(применяется * (диапазон 1N 101N)) ; clojure.lang.BigInt

(применяется * (диапазон 1M 101M)) ; java.math.BigDecimal

0 голосов
/ 07 января 2012

Я не знаю Clojure, но похоже, что для вычисления используются 32-битные или 64-битные целые числа.32-разрядные целые числа со знаком имеют максимальное значение 2^31 - 1 (чуть более 2 * 10 ^ 9).64-разрядные целые числа имеют максимальное значение 2^64 - 1 (чуть более 4 * 10 ^ 18).Значение, которое вы получили от Ruby, намного выше этого.

Очевидно, что Ruby использует другое представление чисел под капотом.

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