【问题标题】:Clojure integer overflowClojure 整数溢出
【发布时间】:2012-08-19 18:09:20
【问题描述】:

我正在运行 Clojure 1.4.0。为什么如果我添加 Integer/MAX_VALUE 和 1,我会得到一个 Long,但如果我将 Integer/MAX_VALUE 添加到自身,我会得到一个异常?

=> (def one 1)
=> (class one)
java.lang.Integer
=> (def max-plus-one (+ Integer/MAX_VALUE one))
=> max-plus-one
2147483648
=> (class max-plus-one)
java.lang.Long

=> (+ Integer/MAX_VALUE Integer/MAX_VALUE)
java.lang.ArithmeticException: integer overflow (NO_SOURCE_FILE:0)

他们不应该以同样的方式行事吗?为什么加两个MAX_VALUE会溢出而加1却不会?

我见过this SO question,但他们的行为与我不同。

【问题讨论】:

    标签: clojure jvm


    【解决方案1】:

    这很奇怪,我在 Ubuntu 12.04 64 位上看到 Clojure 1.4.0 和 Java(TM) SE 运行时环境(构建 1.7.0_06-b24)的不同结果:

    user=> *clojure-version*
    {:major 1, :minor 4, :incremental 0, :qualifier nil}
    user=> (+ Integer/MAX_VALUE Integer/MAX_VALUE)
    4294967294
    user=> (type 1)
    java.lang.Long
    user=> (def max-plus-one (+ Integer/MAX_VALUE one))
    #'user/max-plus-one
    user=> max-plus-one
    2147483648
    user=> (type max-plus-one)
    java.lang.Long
    user=> (+ Integer/MAX_VALUE Integer/MAX_VALUE)
    4294967294
    

    您可以随时查看Java classes which clojure.core uses for numerics,了解功能是如何实现的:

    +运算符的实现在:

    (defn +
      "Returns the sum of nums. (+) returns 0. Does not auto-promote
      longs, will throw on overflow. See also: +'"
      {:inline (nary-inline 'add 'unchecked_add)
       :inline-arities >1?
       :added "1.2"}
      ([] 0)
      ([x] (cast Number x))
      ([x y] (. clojure.lang.Numbers (add x y)))
      ([x y & more]
         (reduce1 + (+ x y) more)))
    

    加长的Java实现:

    final public Number add(Number x, Number y){
        return num(Numbers.add(x.longValue(),y.longValue()));
    }
    

    编辑:使用 Clojure 1.2.1 测试
    我已经使用 Clojure 1.2.1 进行了快速测试,并且使用该版本的 Clojure 我可以完全了解您的行为。

    user=> *clojure-version*
    {:major 1, :minor 2, :incremental 1, :qualifier ""}
    user=> (def one 1)
    #'user/one
    user=> (class 1)
    java.lang.Integer
    user=> (def max-plus-one (+ Integer/MAX_VALUE one))
    #'user/max-plus-one
    user=> max-plus-one
    2147483648
    user=> (class max-plus-one)
    java.lang.Long
    user=> (+ Integer/MAX_VALUE Integer/MAX_VALUE)
    java.lang.ArithmeticException: integer overflow (NO_SOURCE_FILE:0)
    

    我会说您使用 Clojure 1.2.x 进行了测试,而不是 1.4.0。你的 REPL 中 *clojure-version* 的值是多少?

    【讨论】:

    • 你是对的:{:major 1, :minor 2, :incremental 1, :qualifier ""}。我安装了 1.4.0,但似乎 Sublime Text 2 REPL 使用自己的 Clojure。
    • 我过去也有过类似的经历,当时我的机器上有多个版本的 Clojure。
    • 是的,看起来 SublimeREPL 插件运行 lein repl,由于某种原因正在加载 Clojure 1.2.1。
    • 好吧,对于那些好奇为什么lein repl 的版本与你的clj 版本不同的人:github.com/technomancy/leiningen/issues/337stackoverflow.com/questions/10135440/…
    【解决方案2】:

    看起来你已经有了答案,但这里还有一些其他有趣的观点:

    java(所有版本)和 clojure(>1.3.0)的默认行为在溢出时的行为不同

    在java中

    (Long.MAX_VALUE + 1) == Long.MIN_VALUE
    (Integer.MAX_VALUE + 1) == Integer.MIN_VALUE
    
    // cast required to avoid promoting to int
    (Byte.MAX_VALUE + (byte)1) == Byte.MIN_VALUE 
    

    这是因为算术在 jvm 上默认包装

    在 clojure (>1.3.0) 中

    (inc Long.MAX_VALUE) 
       => ArithmeticOverflow
    
    (inc Integer/MAX_VALUE) 
       => a long with value Integer/MAX_VALUE + 1
    (int (inc Integer/MAX_VALUE)) 
       => IllegalArgumentException Value 
          out of range for int: 2147483648 
    

    clojure 确实有一些类似 java 的操作版本

    (unchecked-inc Long.MAX_VALUE) => Long.MIN_VALUE
    

    您可以通过将 *unchecked-math* 设置为 true 来将未选中的操作设为默认值

    (set! *unchecked-math* true)
    (inc Long/MAX_VALUE) 
        => (Long.MIN_VALUE)
    (int (inc Integer/MAX_VALUE)) 
        => (Integer.MIN_VALUE) of type Integer
    

    还有很多其他有趣的(unchecked-*) 操作。

    【讨论】:

      【解决方案3】:

      从 1.3.0 版开始,Clojure 对所有原始数字都使用 Long。你只需要使用更大的数字来获得溢出。

       (def max-plus-one (+ Long/MAX_VALUE one))
      

      【讨论】:

      • 奇怪的是 (class 1) 或 (type 1) 在 cdmckay 的情况下似乎返回 'java.lang.integer' 而不是 long。如果他运行 Clojure 1.4.0,那不应该发生。
      猜你喜欢
      • 1970-01-01
      • 2012-06-27
      • 2022-01-21
      • 2014-01-24
      • 1970-01-01
      • 1970-01-01
      • 2020-10-22
      • 1970-01-01
      相关资源
      最近更新 更多