Julia:Int与Int8对比Int64

时间:2017-06-08 12:25:18

标签: types julia

假设我有一个整数n,它只能取[0, 10]中的值。我是应该将其声明为n::Int来概括,n::Int8n::UInt8是简约还是n::Int64对于64位系统?

请澄清新手的原因,例如:风格,表现。

背景:我正在学习朱莉娅并很快迷失在typeimmutablesyntactic sugar等词汇中!我想我读过这个:https://docs.julialang.org/en/release-0.5/manual/integers-and-floating-point-numbers/

3 个答案:

答案 0 :(得分:13)

区分两种不同的情况很重要。

存储:如果您的某个类型存储n作为其中一个字段,或者作为数组中的值存储,那么您一定要考虑使用Int8UInt8。即使单个值的节省空间可以忽略不计,如果创建了许多类型的实例并将其存储在集合中,那么节省的空间也会迅速变得显着。假设您的Foo类型带有字段n,那么您可以这样做:

struct Foo
    n::UInt8
end

如果将值分配给n对象的Foo字段,它将自动转换为UInt8,如果无法忠实转换该值,则会引发错误:

julia> Foo(123) # Ints are automatically converted to UInt8
Foo(0x7b)

julia> typeof(ans.n)
UInt8

julia> Foo(500) # if too large, an error is raised
ERROR: InexactError()
Stacktrace:
 [1] Foo(::Int64) at ./REPL[1]:2

julia> Foo(-1) # ditto if too small
ERROR: InexactError()
Stacktrace:
 [1] Foo(::Int64) at ./REPL[1]:2

julia> Foo(2π/π)
Foo(0x02)

如果分配的值已经是正确的类型,则不需要检查,因此没有开销。

Dispatch:如果您正在编写一个以n作为参数的函数方法,那么在n上放置类型注释是没有害处的论证在语义上是有道理的。在您描述的情况下,似乎任何类型的整数值都是合理的,因此使用n::Integer可能是合适的。例如,如果要为Foo对象实现已检查的构造函数,则可以执行以下操作:

struct Foo
    n::UInt8

    function Foo(n::Integer)
        0 <= n <= 10 || throw(ArgumentError("n not in [0, 10]: $n"))
        return new(n)
    end
end

如果给出[0,10]之外的值,则抛出错误:

julia> Foo(123)
ERROR: ArgumentError: n not in [0, 10]: 123
Stacktrace:
 [1] Foo(::Int64) at ./REPL[26]:2

julia> Foo(3)
Foo(0x03)

Foo构造适用于任何类型的整数,检查它是否在正确的范围内,然后转换为UInt8。这比Foo的内置构造函数稍微限制一些,它会愉快地使用任何类型的n参数并尝试将其转换为UInt8 - 即使参数不是整数类型。如果需要这种行为,您可以在此处进一步放宽类型签名n::Realn::Number(甚至n::Any,尽管这似乎过多了。)

请注意,紧密键入​​的方法参数没有性能优势 - 实际参数类型的专用代码无论如何都是按需生成的。

答案 1 :(得分:4)

编辑:参考Stefan接受的答案。我的意思是这是对函数调度中类型的使用的响应,但实际上与我自相矛盾(正如我明确说明函数调度实际上应该是Integer)。

我总是使用Int,只是为了它的一般性,但这取决于你的应用程序的性能关键程度。除非您明确需要,否则永远不会Int64。许多函数在Int而不是Integer上调度(虽然建议是在抽象类型上调度),这意味着它们在传递UInt8时会失败(因为Int是{的子类型{1}}和Signed不是因为对类型过于热心会导致问题。 作为一般的经验法则,你应该永远不会对类型有所了解。

答案 2 :(得分:2)

对于新来者(如我自己),阅读abstract type docs可以使事情变得清晰起来。此外,检查以下帮助(<:读取“是'的子类型”):

julia> Int<:Integer
true

julia> UInt<:Integer
true

julia> Int64<:Int
true