gpt4 book ai didi

arrays - SBCL 数组可以将类型化数组作为元素吗?

转载 作者:太空宇宙 更新时间:2023-11-03 18:44:29 24 4
gpt4 key购买 nike

考虑这个简单的例子:

(deftype image nil '(simple-array single-float (100)))

这里我们定义了一个类型的简写,它是一个包含单个 float 的数组。让我们尝试创建一个这样的:

(defparameter tmp
(make-array 100
:element-type 'single-float
:initial-element 0.0))

为了以防万一,让我们检查一下类型:

CL-USER> (type-of tmp)
(SIMPLE-ARRAY SINGLE-FLOAT (100))

一切顺利。让我们看看我们是否可以将这些小数组放在另一个数组中,以使检索更容易,而不是将所有内容都放入一维数组中并最终为计算访问索引而头疼。

(defparameter image-array
(make-array 10
:element-type 'image
:initial-element tmp))

没有办法它会失败,但检查以防万一:

CL-USER> (type-of image-array)
(SIMPLE-VECTOR 10)

糟糕,那根本不是我们想要的。似乎这个新数组默认为默认元素类型:

CL-USER> (array-element-type image-array)
T

这可能意味着应用程序现在不仅要对容器数组元素进行类型检查,还要对子数组的元素进行类型检查,这会影响性能。出现的问题是:

在 SBCL 中是否可以将类型化数组作为数组元素存储在另一个数组中?

编辑:虽然这会返回正确的类型,但 panic 还为时过早:

CL-USER> (type-of (aref image-array 0))
(SIMPLE-ARRAY SINGLE-FLOAT (100))

既然如此,为什么我们从 (array-element-type image-array) 中获取 T 作为元素类型?

最佳答案

ELEMENT TYPE 实际含义的背景知识

如果你给 MAKE-ARRAY 一个元素类型,你要求 Common Lisp 实现创建一个具有优化空间布局(!)的数组,这可能仅限于某些元素类型。您不需要为这个元素类型获取一个数组,而是一个在这个实现中对于这个元素类型最节省空间的数组。

  • 对于数字,实现可能有针对位、8 位字节、16 位字、32 位字等的特殊版本。

  • 它可能有字符数组的特殊版本,比如字符串

  • 它可能有一个或多个 float 类型的特殊版本

是否有更多取决于您使用的实现。

对于任何没有特殊实现的元素类型,元素类型都会升级为T。这意味着数组可以将所有类型的对象作为元素,更大元素(如数组、字符串、结构、CLOS 对象......)将始终存储为指向堆上对象的指针。

特定实现的几个示例:

整数

CL-USER> (upgraded-array-element-type '(integer 0 1))
(UNSIGNED-BYTE 1)
CL-USER> (upgraded-array-element-type '(integer 0 2))
(UNSIGNED-BYTE 2)
CL-USER> (upgraded-array-element-type '(integer 0 3))
(UNSIGNED-BYTE 2)
CL-USER> (upgraded-array-element-type '(integer 0 4))
(UNSIGNED-BYTE 4)
CL-USER> (upgraded-array-element-type '(integer 0 5))
(UNSIGNED-BYTE 4)
CL-USER> (upgraded-array-element-type '(integer 0 7))
(UNSIGNED-BYTE 4)
CL-USER> (upgraded-array-element-type '(integer 0 8))
(UNSIGNED-BYTE 4)
CL-USER> (upgraded-array-element-type '(integer 0 15))
(UNSIGNED-BYTE 4)
CL-USER> (upgraded-array-element-type '(integer 0 16))
(UNSIGNED-BYTE 8)
CL-USER> (upgraded-array-element-type '(integer 0 256))
(UNSIGNED-BYTE 16)
CL-USER> (upgraded-array-element-type '(integer 0 4423423))
(UNSIGNED-BYTE 32)
CL-USER> (upgraded-array-element-type '(integer 0 4423423423423))
(UNSIGNED-BYTE 64)
CL-USER> (upgraded-array-element-type '(integer 0 4423423423423423423423423423423))
T

字符

CL-USER> (upgraded-array-element-type 'character)
CHARACTER

float

CL-USER> (upgraded-array-element-type 'single-float)
SINGLE-FLOAT
CL-USER> (upgraded-array-element-type 'long-float)
DOUBLE-FLOAT

数组

CL-USER> (upgraded-array-element-type 'array)
T

即使您要求更具体版本的数组作为元素,您也很可能得到 T 作为答案。

何时请求特殊数组

最重要的原因是节省空间。如果只有位,一般数组可以存储位,但位向量会节省大量空间。

但是:具有特殊元素类型的数组的操作可能较慢。在安全代码的运行时,可能会有额外的类型检查,并且更改/读取元素的操作可能需要较慢的处理器指令。

Common Lisp 数组的局限性

因此,Common Lisp 没有为结构数组、向量、CLOS 对象等优化存储布局。由于存储的每个元素都有一个指针,访问总是需要间接访问,并且没有任何东西可以保证这些对象是以线性顺序存储在内存中。在数组中以线性顺序存储指向它们的指针。

检查您的实现是否优化了浮点(单、双、长...)数组的空间布局。

多维数组

Common Lisp 支持最多 ARRAY-RANK-LIMIT 的真正多维数组(ABCL 在我的 ARM 上最多有 8 个维度,其他一些实现支持更多维度)。这些多维数组也可以有专门的元素类型。

关于arrays - SBCL 数组可以将类型化数组作为元素吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45550984/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com