Julia语言中的通用浮点类型是什么?

3
我的问题很简单,julia语言中是否有通用的Float类型?例如对于Integer类型,我们可以直接写Int,在32位系统中它将被翻译为Int32,在64位系统中则被翻译为Int64。但是对于Float类型,如下面的示例函数所示:
function bb(n)
    b = Array{Float64}(n) 
    b[1] = 0.9999
    for i = 2:n
        @inbounds b[i] = b[i-1] * 0.9999
    end    
    println(b[n])
end

bb(10^3)
@time bb(10^3)
@time bb(10^8)

它提供以下定时结果以及总内存分配情况:
0.9048328935585562
0.9048328935585562
  0.000100 seconds (135 allocations: 15.750 KB)
2.4703e-320
  3.230642 seconds (14 allocations: 762.940 MB, 1.51% gc time)

现在将第一行更改为b = Array{AbstractFloat}(n),然后查看极大的计时和内存分配:
0.9048328935585562
0.9048328935585562
  0.003564 seconds (2.13 k allocations: 46.953 KB)
2.4703e-320
  351.068176 seconds (200.00 M allocations: 3.725 GB, 0.74% gc time)

我无法使用 b = Array{Float}(n),我的解决方案是使用这种不太优雅的记号 b = Array{typeof(1.0)}(n)


简短回答:使用Float64。如果您坚持使用,请执行const Float = typeof(1.0),然后在之后使用Float,但标准是Float64(顺便说一下,const是写typealias的新方式)。此外,浮点数是一种折衷方案。如果您有特殊需求,则可能需要仔细考虑要使用哪种数字类型,Julia中有很多选择。 - Dan Getz
@DanGetz -- 感谢您的回复。这引出了另一个问题,为什么Julia团队没有将那个优雅的 const Float = typeof(1.0) 添加到Julia核心中呢?这样人们就可以更轻松地编写 Float 而不用考虑底层系统。 - AboAmmar
1个回答

11

您对抽象浮点数的问题与32位或64位无关。

Julia没有匹配IntFloat,因为浮点数字面值始终是Float64。
即在64位或32位系统上,typeof(1.0)==Float64。 (要使用Float32文本使用1.0f0

如果您真的想要一个,您需要将其定义为

@static if Sys.WORDSIZE == 64
    const Float = Float64
else
    const Float = Float32
end

但这似乎并没有什么用处,因为它对应不上任何东西。 即使在32位CPU上,浮点数运算的实现通常也是64位的,因此它也不会成为更接近硬件的映射。
参见:Discourse 上的这个帖子
在32位系统上使用Float32,64位系统上使用Float64 没有任何优势。 如果您不需要精度,使用Float32 有优势 - 最重要的一个是减少内存分配 - 这将减少分配和进程间通信所需的时间。
关于性能问题: b = Array{AbstractFloat}(n) 的性能差是因为创建了一个包含抽象类型的容器。 请参见 性能提示:避免具有抽象类型参数的容器 这些很慢,因为它们基本上是指针数组 - 每次与元素交互时都需要解引用指针。 这是因为数组b已被声明为可能包含任意数量不同类型的元素。其中一些可能是Float16,其他可能是Float32,有些甚至可以是BigFloat或ArbFloat {221}。 因此,包含抽象类型的容器处理起来很慢,因为它们是指针数组。
因此,编写b = Array{typeof(1.0)}(n)与编写b = Array{Float64}(n)完全等效。 这里没有做任何事情。 因此,这显然不是解决您真正问题的方法。
假设您真正的问题在于想要指定返回的类型,那么应将其作为参数传递:
function bb(T, n)
    b = Array{T}(n) 
    b[1] = 0.9999
    for i = 2:n
        @inbounds b[i] = b[i-1] * 0.9999
    end    
    println(b[n])
end

你可以使用(例如)bb(Float32, 100)进行调用。

所有的数学计算都在Float64中进行,因为它是使用Float64字面量指定的,但当你将它赋值给数组时,convert(T,...)将会被隐式调用。

或者,你可能想传入这些值,并推断出类型:

function bb(n, b1::T)
    b = Array{T}(n) 
    b[1] = b1
    for i = 2:n
        @inbounds b[i] = b[i-1] * b1
    end    
    println(b[n])
end

Call that with: bb(100, 0.9999f0)


+1 for the discourse link. This does come up often. I feel the solution might be more along matlab lines, i.e. const Single = Float32; const Double = Float64 rather than const Float = Float64 (I do agree that just saying 'float' would be confusing to people thinking in c++) - Tasos Papastylianou
2
我不会在Base中定义更多内容。我只会让它出错,让人们通过谷歌搜索并找到适当的文档(例如这个答案和Discord帖子)。Float64Float32是理想的名称。使用其他任何名称都是不必要的。(我希望Julia永远不会变成TIMTOWTDI) - Frames Catherine White
很好的回答@LyndonWhite,所以我的理解是,如果我写Float64在32位系统上也能正常工作?我的主要关注点是编写通用代码并保持高性能。顺便说一句,Julia拥有伟大的社区,我很荣幸成为其中的一员。 - AboAmmar
你是正确的,Float64 在 32 位系统上也可以正常工作。 - Frames Catherine White

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接