表題

一様数値ベクタ型

著者

Marc Feeley

状態

この SRFI は現在「確定」の状態である。 SRFI の各状態の説明については ここ を参照せよ。 この SRFI に関する議論については メーリングリストのアーカイブ を参照せよ。

概要

この SRFI では、要素が同じ数値型 (符号付き、符号なし、正確整数、ある精度をもつ不正確実数) のベクタを表すデータ型について述べる。 これらのデータ型は Scheme のベクタ型と同様の操作をサポートするが、 Scheme のベクタ型とは別個のデータ型である。 readwrite 手続き、および、プログラム パーサでサポートしなければならない外部表現についても規定する (すなわち、プログラム中に一様ベクタのリテラル表現を記述することができる)。

論拠

リストと同様に、Scheme のベクタは異種混合が可能であり、要素のデータ型に制限を加えることはない。 しかし、すべての要素が同じデータ型をもつアプリケーションでは、この汎用性は不要なものである。 このようなアプリケーションにとっては Scheme のベクタは理想的ではない。 気の利いた静的解析を行うコンパイラがない場合、ベクタは要素を何らかの方法でまとめて管理するが、 その方法はメモリ効率が悪く、要素へのアクセス速度も遅いものになる。 さらに、一様ベクタは低レベル ライブラリ (たとえば、バイナリ ブロック入出力) と連携する場合や、 一様ベクタをサポートする外部言語と相互運用する場合に便利である。 また、一様ベクタを使用することにより、ある種のエラーを早い段階で検出することが可能になる。

この SRFI では、いくつかの一様ベクタ データ型を定義する。要素が数値型 (正確整数 (exact integer) または不正確実数 (inexact real)) で、その精度と表現が現在のほとんどのコンピュータ アーキテクチャのハードウェアで効率よく実装できるような、 最も実用的なケースをカバーする (符号付きおよび符号なしの 8、16、32、64 ビット整数、32 ビットおよび 64 ビットの浮動小数点数)。

仕様

以下に 8 つの正確整数一様ベクタを示す。これらを整数ベクタ (integer vector) という。
データ型 要素の型
s8vector 符号付き正確整数。値の範囲は -(2^7) ~ (2^7)-1
u8vector 符号なし正確整数。値の範囲は 0 ~ (2^8)-1
s16vector符号付き正確整数。値の範囲は -(2^15) ~ (2^15)-1
u16vector符号なし正確整数。値の範囲は 0 ~ (2^16)-1
s32vector符号付き正確整数。値の範囲は -(2^31) ~ (2^31)-1
u32vector符号なし正確整数。値の範囲は 0 ~ (2^32)-1
s64vector符号付き正確整数。値の範囲は -(2^63) ~ (2^63)-1
u64vector符号なし正確整数。値の範囲は 0 ~ (2^64)-1

以下に不正確実数一様ベクタの 2 つのデータ型を示す。これらを浮動ベクタ (float vector) という。
データ型 要素の型
f32vector 不正確実数
f64vector 不正確実数

この 2 つの浮動ベクタ型の違いは、f64vector が少なくとも f32vector の精度と同じだけの精度を保証するという点だけである (詳細については「実装」のセクションを参照せよ)。

この SRFI に準拠する Scheme システムは、上記すべての一様ベクタ型をサポートする必要はない。 しかし、Scheme システムが Scheme の不正確実数をサポートしているのであれば (その精度については問わない)、f32vectorf64vector をサポートしなければならない。 また、Scheme システムの正確整数型が、特定の整数ベクタの要素の値を保持できるほど大きいのであれば、その整数ベクタをサポートしなければならない。 したがって、多倍長整数 (bignum) をサポートする Scheme システムはすべての整数ベクタ型を実装しなければならず、値の範囲が -(2^29) ~ (2^29)-1 の小さな整数のみをサポートするシステムでは s8vectoru8vectors16vectoru16vector だけを実装すればよい (このようなケースは、整数を 32 ビット固定長で扱い、そのうちの 2 ビットをタグ用に使用するシステムで有り得ることである) 。 Scheme システムがどの数値型をサポートするかを検査するには、string->number 手続きを使用することができる (たとえば (string->number "0.0") は、不正確実数をサポートしていなければ #f を返す) 。

各一様ベクタ型は、readwrite 手続きおよびプログラム パーサでサポートされる外部表現をもつ。 また各一様ベクタ型は、Scheme の非一様ベクタで利用可能な手続きと同様の定義済み手続きを利用できる。

TAG を { s8, u8, s16, u16, s32, u32, s64, u64, f32, f64 } のいずれかとする。データ型 TAGvector がサポートされている場合:

  1. データ型 TAGvector のインスタンスの外部表現は #TAG( ...elements... ) とする。

    たとえば、#u8(0 #e1e2 #xff) は長さ 3 の u8vector で、0、100、255 を含む。 #f64(-1.5) は長さ 1 の f64vector で、-1.5 を含む。

    標準 Scheme では #f32()#f32() の 3 つのオブジェクトとして解釈するので、浮動ベクタの構文は、標準 Scheme と競合することになる。 この理由から、この SRFI に準拠することは標準 Scheme に少し違反することになる。

    この外部表現はプログラムのソース コードに記述することもできる。たとえば、(set! x '#u8(1 2 3)) と記述すると、x にオブジェクト #u8(1 2 3) を設定することになる。 一様ベクタのリテラルは、非一様ベクタのリテラルと同様にクォートする必要がある。一様ベクタは擬似クォート (quasiquote) の中に現れることはできるが、unquote または unquote-splicing フォームを含んではいけない (つまり、`(,x #u8(1 2)) は正しいが、`#u8(1 ,x 2) は不正である) 。 この制約は、プログラムをパースするために read 手続きを使用する多くの Scheme システムに適合するためのものである。

  2. 以下の定義済み手続きが利用可能である。
    1. (TAGvector? obj)
    2. (make-TAGvector n [ TAGvalue ])
    3. (TAGvector TAGvalue...)
    4. (TAGvector-length TAGvect)
    5. (TAGvector-ref TAGvect i)
    6. (TAGvector-set! TAGvect i TAGvalue)
    7. (TAGvector->list TAGvect)
    8. (list->TAGvector TAGlist)
    ここで obj は任意の Scheme オブジェクト、n は非負の正確整数、i はベクタの長さより小さい非負の正確整数、TAGvectTAGvector データ型のインスタンス、TAGvalueTAGvector データ型の要素として格納できる数値、TAGlistTAGvector データ型の要素として格納できる数値のリストである。

    TAGvalueTAGvector データ型の要素と同じ型でなければエラーである (たとえば、正確整数を f64vector に渡した場合) 。 埋め合わせる初期値を指定しない場合、ベクタの内容は規定されないが、 ベクタの個々の値はそのベクタ型の値の範囲を超えないことが保証される。

実装

ここに示す一様ベクタ型では、符号付きの正確整数の実装に 2 の補数表現を使用した 8、16、32、64 ビット要素を使用し、不正確実数の実装に単精度および倍精度の IEEE-754 浮動小数点表現を使用している。 これは最近の多くのバイト アドレッシング方式のマシンでは実用的な実装であるが、これらの数値型をサポートしないマシンにおいては別の実装が可能である。 (たとえば CRAY-T90 には 32 ビット浮動小数点表現がなく、また 64 ビット浮動小数点表現は IEEE-754 に準拠していない。そのため、f32vectorf64vector データ型はともに 64 ビット浮動小数点数として実装することがあり得る。)

一様ベクタの定義済み手続きのポータブルな実装として、Scheme の非一様ベクタをベースにすることができる。 以下に例として s8vector の実装を示すが、ここではエラー検査は省略している。
(define s8vector? #f)
(define make-s8vector #f)
(define s8vector #f)
(define s8vector-length #f)
(define s8vector-ref #f)
(define s8vector-set! #f)
(define s8vector->list #f)
(define list->s8vector #f)

(let ((orig-vector? vector?)
      (orig-make-vector make-vector)
      (orig-vector vector)
      (orig-vector-length vector-length)
      (orig-vector-ref vector-ref)
      (orig-vector-set! vector-set!)
      (orig-vector->list vector->list)
      (orig-list->vector list->vector)
      (orig-> >)
      (orig-eq? eq?)
      (orig-+ +)
      (orig-null? null?)
      (orig-cons cons)
      (orig-car car)
      (orig-cdr cdr)
      (orig-not not)
      (tag (list 's8)))

  (set! s8vector?
    (lambda (obj)
      (and (orig-vector? obj)
           (orig-> (orig-vector-length obj) 0)
           (orig-eq? (orig-vector-ref obj 0) tag))))

  (set! make-s8vector
    (lambda (n . opt-fill)
      (let ((v (orig-make-vector
                 (orig-+ n 1)
                 (if (orig-null? opt-fill) 123 (orig-car opt-fill)))))
        (orig-vector-set! v 0 tag)
        v)))

  (set! s8vector
    (lambda s8list
      (orig-list->vector (orig-cons tag s8list))))

  (set! s8vector-length
    (lambda (s8vect)
      (orig-+ (orig-vector-length s8vect) -1)))

  (set! s8vector-ref
    (lambda (s8vect i)
      (orig-vector-ref s8vect (orig-+ i 1))))

  (set! s8vector-set!
    (lambda (s8vect i s8value)
      (orig-vector-set! s8vect (orig-+ i 1) s8value)))

  (set! s8vector->list
    (lambda (s8vect)
      (orig-cdr (orig-vector->list s8vect))))

  (set! list->s8vector
    (lambda (s8list)
      (orig-list->vector (orig-cons tag s8list))))

  (set! vector?
    (lambda (obj)
      (and (orig-vector? obj)
           (orig-not (and (orig-> (orig-vector-length obj) 0)
                          (orig-eq? (orig-vector-ref obj 0) tag)))))))

一様ベクタの外部表現を処理するために、Scheme システムの readwrite 手続きおよびプログラム パーサも拡張する必要がある。 read 手続きおよびプログラム パーサが #s8#f32 などのプレフィックスを認識しなければならないことを除けば、その実装は非一様ベクタの実装に非常に近いものとなる。 (これは次のようにして検査できる。シャープ記号の次にシンボル先頭に許される文字が現れたときに、そのシンボルが tfs8f32 などであるか検査し、一様ベクタのプレフィックスである場合は、次の文字が開き丸括弧であるかを検査する)。

著作権

Copyright (C) Marc Feeley (1999). All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


編集者: Shriram Krishnamurthi