[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.25 gauche.uvector - ユニフォームベクタ

Module: gauche.uvector

SRFI-4(SRFI-4)に定義されている、 要素が同一の数値型であるようなベクタを提供します。

Gaucheの実装は、SRFI-4の仕様を次のように拡張しています。

通常のベクタではなくSRFI-4ベクタを使うことにより得られる利点がいくつかあります。 まず、SRFI-4ベクタは通常のベクタよりもコンパクトです。 いくつかのオペレーション(特に、Gaucheの拡張仕様であるベクタ上の数値演算)では、 型検査と型変換を個々の要素に対して行わなくても良いため、 極めて効率の良い演算が可能です。さらに、 数値の配列を扱う外部のライブラリとのインタフェースが容易です。 例えば、GaucheのOpenGLバインディングではSRFI-4ベクタを多用しています。

以下の10タイプのベクタが定義されます。

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 の間の正確な整数であるベクタ

f16vector

要素が、16ビット浮動小数点数(half floatとしても知られている)で表現 し得るような不正確な実数であるベクタ

f32vector

要素が、GaucheをコンパイルしたCコンパイラのfloatで表現し得るような 不正確な実数(通常IEEE単精度浮動少数点数)であるベクタ

f64vector

要素が、GaucheをコンパイルしたCコンパイラのdoubleで表現し得るような 不正確な実数(通常IEEE倍精度浮動少数点数)であるベクタ

ベクタの型が許す範囲外の値を格納しようとした場合、通常はエラーとなります。 いくつかの手続きは省略可能な引数clampによって、 そのような場合に別のふるまいを指定することができます。 clampには以下のいずれかの値を与えることが出来ます。

#f

デフォルト (エラーを通知)

high

高い方の値をクランプ、すなわち、格納しようとする値が許される値の最大値より大きかった 場合は、可能な最大値を代わりに格納します。

low

低い方の値をクランプ、すなわち、格納しようとする値が許される値の最小値より大きかった 場合は、可能な最小値を代わりに格納します。

both

高いほうと低いほうの両方の値をクランプします。

 
(list->u8vector '(-1))         ⇒ error
(list->u8vector '(-1) 'low)    ⇒ #u8(0)
(list->u8vector '(-1) 'high)   ⇒ error
(list->u8vector '(3000) 'high) ⇒ #u8(255)
(list->u8vector '(-100 20 300) 'both) ⇒ #u8(0 20 255)

以下の記述では、TAGs8, u8, s16, u16, s32, u32, s64, u64, f16, f32, f64 のいずれにも置き換えて読むことができるものとします。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.25.1 ユニフォームベクタの基本操作

Builtin Class: <TAGvector>

TAGvectorのクラス。<sequence>を継承します。

Reader Syntax: #TAG(n …)

リテラルの単一型のベクタを記述します。

 
#s8(3 -2 4)
#u32(4154 88357 2 323)
#f32(3.14 0.554525 -3.342)
Function: TAGvector? obj

[SRFI-4] objTAGvectorなら#tを、そうでなければ#fを返します。

Function: TAGvector x

[SRFI-4] 数値x … を要素に持つTAGvectorを作成して返します。 正確な整数のベクタに対しては、数値は正確な整数でなければならず、 また有効な範囲内の値でなければなりません。

 
(s8vector 1 2 3) ⇒ #s8(1 2 3)
Function: make-TAGvector len &optional fill

[SRFI-4] 長さlenTAGvectorを作成して返します。各要素はfillで 初期化されます。正確な整数のベクタに対しては、fillは正確な整数でなければならず、 また有効な範囲内の値でなければなりません。 fillが省略された場合、各要素の初期値は不定です。

 
(make-u8vector 4 0) ⇒ #u8(0 0 0 0)
Function: TAGvector-length vec

[SRFI-4] TAGvector vecの長さを返します。

モジュールgauche.collectionをインポートしていれば、 vecの長さを知るのに、総称関数size-ofを使うこともできます (gauche.collection - コレクションフレームワーク参照)。

 
(s16vector-length '#s16(111 222 333)) ⇒ 3

(use gauche.collection)
(size-of '#s16(111 222 333)) ⇒ 3
Function: TAGvector-ref vec k &optional fallback

[SRFI-4+] TAGvector veck番目の要素を返します。

kが有効な範囲外であった場合、通常はエラーが通知されますが、 省略可能な引数fallbackが与えられている場合はそれが返されます。

モジュールgauche.collectionをインポートしていれば、 総称関数refを使うこともできます。

 
(u16vector-ref '#u16(111 222 333) 1) ⇒ 222

(use gauche.collection)
(ref '#u16(111 222 333) 1) ⇒ 222
Function: TAGvector-set! vec k n &optional clamp

[SRFI-4+] TAGvector veck番目の要素に数値nをセットします。 省略可能な引数clampが、nが正しい範囲外の数であった場合の動作を指定します。 デフォルトではエラーが通知されます。

モジュールgauche.collectionをインポートしていれば、 総称関数refのsetter手続きを使うこともできます。

 
(let ((v (s32vector -439 852 8933)))
  (s32vector-set! v 1 4)
  v)
 ⇒ #s32vector(-439 4 8933)

(use gauche.collection)
(let ((v (s32vector -439 852 8933)))
  (set! (ref v 1) 4)
  v)
 ⇒ #s32vector(-439 4 8933)
Function: TAGvector-fill! vec fill &optional start end

vecのすべて要素にfillをセットします。 startendで要素の範囲を指定することも出来ます。

Function: TAGvector-copy vec &optional start end

ベクタvecをコピーします。 省略可能な引数startendが与えられた場合、 それらは取り出される要素の範囲を制限します。

 
(u8vector-copy '#u8(1 2 3 4))     ⇒ #u8(1 2 3 4)
(u8vector-copy '#u8(1 2 3 4) 2)   ⇒ #u8(3 4)
(u8vector-copy '#u8(1 2 3 4) 1 3) ⇒ #u8(2 3)
Function: TAGvector-copy! target tstart source &optional sstart send

target および source はともに TAGvector でなければ なりません。さらに、target は変更可能でなければなりません。 この手続きは、startの要素を、インデックスsstartから(これを含み) send までを、target へインデックス tstartからコピーします。 sstartおよびtstartは省略可能で、その場合には、それぞれ、 0 および sourceの長さが仮定されます。

 
(let ((target (u8vector 0 1 2 3 4 5 6)))
  (u8vector-copy! target 2 '#u8(10 11 12 13 14) 1 4)
  target)
 ⇒ #u8(0 1 11 12 13 6)

もし、コピー元のベクタの sstartsend の間にある要素の 数がコピー先のベクタのtstart以降の部分よりも大きければ、超過分の ベクタはだまって捨てられます。

注意事項: この手続きは以前はユニフォームベクタ target および source のみを引数としてとり、source の内容を target へ コピーするためだけに使われました。両方のベクタは同じ型で、同じ長さでなけ ればなりませんでした。この API は string-copy! (SRFI-13) および vector-copy! (SRFI-43)にあわせて現在の形式に改訂されています。 旧来のインタフェースもバックワードコンパチビリティのためにサポートされて いますが、これは廃止予定で、将来のリリースではサポートされなくなります。

コレクションやシーケンスフレームワークを使うと、さらに様々な操作を 行うことができます。

 
(use gauche.collection)
(use gauche.sequence)

(fold + 0 '#s32(1 2 3 4)) ⇒ 10

(map-to <f32vector> * '#f32(3.2 1.1 4.3) '#f32(-4.3 2.2 9.4))
  ⇒ #f32(-13.760001 2.420000 40.420002)

(subseq #u32(1 4 3 4 5) 2 4) ⇒ #u32(3 4)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.25.2 ユニフォームベクタの変換

Function: TAGvector->list vec &optional start end

[SRFI-4+] TAGvector vecをリストに変換します。 省略可能な引数startendが与えられた場合、 それらは取り出される要素の範囲を制限します。

モジュールgauche.collectionをインポートしていれば、 総称関数coerce-toを使うこともできます。

 
(u32vector->list '#u32(9 2 5)) ⇒ (9 2 5)

(use gauche.collection)
(coerce-to <list> '#u32(9 2 5)) ⇒ (9 2 5)
Function: TAGvector->vector vec &optional start end

TAGvector vecをベクタに変換します。 省略可能な引数startendが与えられた場合、 それらは取り出される要素の範囲を制限します。

モジュールgauche.collectionをインポートしていれば、 総称関数coerce-toを使うこともできます。

 
(f32vector->vector '#f32(9.3 2.2 5.5))   ⇒ #(9.3 2.2 5.5)
(f32vector->vector '#f32(9.3 2.2 5.5) 2) ⇒ #(5.5)

(use gauche.collection)
(coerce-to <vector> '#f32(9.3 2.2 5.5)) ⇒ #(9.3 2.2 5.5)
Function: list->TAGvector list &optional clamp

[SRFI-4+] リストlistTAGvectorに変換します。 省略可能な引数clampが、リスト内の要素が正しい範囲外の数であった場合の 動作を指定します。

モジュールgauche.collectionをインポートしていれば、 総称関数coerce-toを使うこともできます。

 
(list->s64vector '(9 2 5)) ⇒ #s64(9 2 5)

(use gauche.collection)
(coerce-to <s64vector> '(9 2 5)) ⇒ #s64(9 2 5)
Function: vector->TAGvector vec &optional start end clamp

ベクタvecTAGvectorに変換します。 省略可能な引数startendが与えられた場合、 それらは取り出される要素の範囲を制限します。 省略可能な引数clampが、ベクタ内の要素が正しい範囲外の数であった場合の 動作を指定します。

モジュールgauche.collectionをインポートしていれば、 総称関数coerce-toを使うこともできます。

 
(vector->f64vector '#(3.1 5.4 3.2)) ⇒ #f64(3.1 5.4 3.2)

(use gauche.collection)
(coerce-to <f64vector> '#(3.1 5.4 3.2)) ⇒ #f64(3.1 5.4 3.2)
Function: string->s8vector string &optional start end
Function: string->u8vector string &optional start end

与えられた文字列の内部表現のバイト列と同じバイト列を持つs8vectorもしくは u8vectorを返します。省略可能な範囲引数startendは、 変換される文字列中の文字位置を指定します。

これらの手続きは、文字を構成するバイト列をランダムにアクセスしたい場合などに 有用です。

 
(string->u8vector "abc") ⇒ #u8(97 98 99)

;; 内部コードがEUCの場合
(string->u8vector "いろは") ⇒ #u8(164 164 164 237 164 207)
Function: string->s8vector! target tstart string &optional start end
Function: string->u8vector! target tstart string &optional start end

target は、それぞれ s8vector あるいは u8vector でなければなりません。 target は、変更可能でなければなりません。 string の生バイト表現を target へインデックス tstart からコピーします。

target を返します。

 
(let ((target (make-u8vector 10 0)))
  (string->u8vector! target 3 "abcde"))
 ⇒ #u8(0 0 0 97 98 99 100 101 0 0)
Function: s8vector->string vec &optional start end
Function: u8vector->string vec &optional start end

与えられたs8vectorもしくはu8vector vecのバイト列と同じ内部バイト列を 持つ文字列を作成して返します。省略可能な範囲引数startendは、 vec中の変換されるべき範囲をバイト位置で指定します。

vec中のバイト列が文字列の内部表現として不正な値を持っていた場合は、 不完全な文字列が返されます。

Function: string->s32vector string &optional start end
Function: string->u32vector string &optional start end

与えられた文字列stringの各文字の内部コードを値として持つ s32vectorもしくはu32vectorを返します。 省略可能な範囲引数startendは、 変換される文字列中の文字位置を指定します。

これらの手続きは、文字列中の文字をランダムにアクセスする場合に便利です。

Function: s32vector->string vec &optional start end
Function: u32vector->string vec &optional start end

startendを考えなければ、 これらの手続きは次のコードのような動作をします:

 
(lambda (vec) (map-to <string> integer->char vec)))

省略可能な範囲引数startendは、 vec中の変換されるべき範囲を指定します。

Function: uvector-alias uvector-class vec &optional start end

この手続きは、クラスがuvector-classであり、 ユニフォームベクタvecのメモリ領域を共有するような 新しいユニフォームベクタを作成して返します。 省略可能な引数startendが与えられた場合は vecの内容のうちそれらのインデックスで指定される範囲のみが使われます。 メモリ領域が共有されているので、vecに加える変更は 新しいベクタから見えますし、その逆も可能です。

クラスuvector-classはユニフォームベクタのクラスでなければなりませんが、 vecのクラスと一致している必要はありません。 そのような場合は、新しいベクタはvecと同じメモリ領域の値を 異なる値と解釈するかもしれません。 例えば、次のコードはGaucheが走っているマシンが リトルエンディアンであるかビッグエンディアンであるかを判定します。

 
(let ((u8v (uvector-alias <u8vector> #u32(1))))
  (if (zero? (u8vector-ref u8v 0))
      'big-endian 
      'little-endian))

uvector-classがs8vectorかu8vector以外の場合、 新しいベクタが指す領域は、そのベクタの要素のアラインメントの要請に したがっていなければなりません。 ユニフォームベクタの開始点は常に全てのユニフォームベクタのアラインメント要請を 満たします。したがって、例えばu8vectorからu32vectorを作成する場合、 startおよびendは4の倍数でなければなりません (あるいは、start/endが省略された場合、vecの長さが 4の倍数でなければなりません)。 与えられたパラメータでアラインメントの要請が満たせない場合はエラーが通知されます。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.25.3 ユニフォームベクタの数値演算

Function: TAGvector-add vec val &optional clamp
Function: TAGvector-add! vec val &optional clamp
Function: TAGvector-sub vec val &optional clamp
Function: TAGvector-sub! vec val &optional clamp
Function: TAGvector-mul vec val &optional clamp
Function: TAGvector-mul! vec val &optional clamp

要素毎の計算手続きです。vecTAGvectorでなければなりません。 また、valvecと同じ長さのTAGvectorかベクタかリスト、 あるいは数値(整数ベクタに対しては正確な整数、実数ベクタに対しては実数) でなければなりません。

valTAGvectorの場合、 vecと対応する要素毎に加算、減算、乗算が行われ、 結果がTAGvectorとして返されます。 破壊的なバージョン(名前に`!'がついているもの)では、vecが 結果を格納するために再利用されます。 演算の結果がTAGvectorの要素の値域外になった場合の動作は 省略可能な引数clampによって指定されます。 (f32vectorとf64vectorでは、値域外になった要素にはinfinityが格納され、 clampの値は無視されます)。

valが数値である場合、vecの各要素とその数値の間で演算が行われます。

 
(s8vector-add '#s8(1 2 3 4) '#s8(5 6 7 8)) ⇒ #s8(6 8 10 12)
(u8vector-sub '#u8(1 2 3 4) '#u8(2 2 2 2)) ⇒ error
(u8vector-sub '#u8(1 2 3 4) '#u8(2 2 2 2) 'both) ⇒ #u8(0 0 1 2)

(f32vector-mul '#f32(3.0 2.0 1.0) 1.5) ⇒ #f32(4.5 3.0 1.5)
Function: TAGvector-div vec val
Function: TAGvector-div! vec val

要素毎の除算です。これらはf32vectorとf64vectorのみに対して定義されます。 valvecと同じ大きさのTAGvectorかベクタかリスト、 あるいは実数でなければなりません。

 
(f32vector-div '#f32(1.0 2.0 3.0) 2.0) ⇒ #f32(0.5 1.0 1.5)
Function: TAGvector-and vec val
Function: TAGvector-and! vec val
Function: TAGvector-ior vec val
Function: TAGvector-ior! vec val
Function: TAGvector-xor vec val
Function: TAGvector-xor! vec val

要素毎の論理(ビット)演算です。 これらの手続きは整数ベクタに対してのみ定義されています。 valvecと同じ大きさのTAGvectorかベクタかリスト、 あるいは正確な整数でなければなりません。vecの各要素と、対応するvalの要素 (valが非スカラー値の場合)もしくはval自身 (valが整数の場合)とのビット毎のand, inclusive orまたはexclusive or が計算され、結果がTAGvectorで返されます。 破壊的なバージョン(名前に`!'がついているもの)では、vecが 結果を格納するために再利用されます。

Function: TAGvector-dot vec0 vec1

ふたつのTAGvectorの内積を計算します。 vec0vec1の長さは等しくなければなりません。

Function: TAGvector-range-check vec min max

vecTAGvectorでなければなりません。 minmaxはそれぞれ、vecと同じ長さのTAGvector、 ベクタ、リストのいずれかか、実数もしくは#fでなければなりません。

vecの各要素に対して、この手続きはそれが対応するminvalmaxval の間にあるかどうかを検査します。minvalmaxvalも範囲に含みます。 ここで、minvalmaxvalは、min/maxが非スカラー値 であればvecの要素に対応するそれぞれの要素、 min/maxが数値であればその数値そのものです。 min#fの場合、最小値はマイナス無限大と考えられます。 max#fの場合、最大値はプラス無限大と考えられます。

vecの全ての要素が範囲内であった場合は#fが返されます。 そうでなければ、範囲を外れた要素のうちもっとも左のもののvec内での インデックスが返されます。

 
(u8vector-range-check '#u8(3 1 0 2) 0 3)  ⇒ #f
(u8vector-range-check '#u8(3 1 0 2) 1 3)  ⇒ 2

(u8vector-range-check '#u8(4 32 64 98) 0 '#u8(10 40 70 90))
  ⇒ 3

;; Range check in a program
(cond
 ((u8vector-range-check u8v 1 31)
  => (lambda (i)
      (errorf "~sth vector element is out of range: ~s"
              i (u8vector-ref u8v i))))
 (else (do-something u8v)))
Function: TAGvector-clamp vec min max
Function: TAGvector-clamp! vec min max

vecTAGvectorでなければなりません。 minmaxはそれぞれ、vecと同じ長さのTAGvector、 ベクタ、リストのいずれかか、実数もしくは#fでなければなりません。

TAGvector-range-checkと同じように、この手続きはvecの各要素が minおよびmaxで指定される最小値と最大値の間にあるかどうかを 検査します。要素が最小値より小さかった場合はそれが最小値に置き換えられます。 要素が最大値より大きかった場合はそれが最大値に置き換えられます。

TAGvector-clampはvecのコピーを作ってそれに対して クランプ操作を行います。TAGvector-clamp!はvecを直接 変更します。どちらもクランプ操作が行われた後のTAGvectorを返します。

 
(s8vector-clamp '#s8(8 14 -3 -22 0) -10 10) ⇒ #s8(8 10 -3 -10 0)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.25.4 ユニフォームベクタのブロック入出力

ユニフォームベクタは、メモリの固まりを抽象化しているものと考えることも できます。それなら、それをバイナリI/Oに使えないでしょうか。もちろんできます。

Function: read-block! vec &optional iport start end endian

与えられた入力ポートiportからデータの固まりを読みだし、それを ユニフォームベクタvecに格納します。 どんな種類のユニフォームベクタでも与えることができます。 省略可能な引数startendが与えられた場合は、 それらがvec中でデータが格納されるべき領域のインデックスの範囲を 示します。endについては-1でvecの最後を示すこともできます。 その範囲外のvecの値は変更されません。 startendが与えられなかった場合はvec全体が使われます。 iportが省略された場合はカレント入力ポートが使われます。

要求された領域を埋め終る前に入力がEOFに達した場合は、ベクタの残りの部分は 変更されません。

read-block!が呼ばれた時既にiportがEOFに達していた場合は EOFが、そうでなければ読まれた要素の数 (バイト数ではありません) が返されます。

iportがバッファードポートであり、そのバッファリングモードが `modest' か `none' であった場合、read-block!iportが EOFに達していなくても、vecを埋める前に戻ることがあります (バッファリングモードについてはファイルポート)を参照して下さい。 パイプやネットワークに接続されたポートはデフォルトでそのように振舞います。 もし、十分なデータが到着することがわかっており、vecを確実に埋めたい場合は ポートのバッファリングモードを`full'に変更して下さい。

データはバイトストリームとして読まれるので、 s8vectorとu8vector以外のユニフォームベクタを与えた場合は 結果がエンディアンに影響を受けることに注意して下さい。 例えば入力が#x01, #x02, #x03, #x04というバイトシーケンスだったと します。これをu32vectorに読み込んだ場合、最初の要素は ビッグエンディアンでは#x01020304になりますが、 リトルエンディアンでは#x04030201となるでしょう。 デフォルトではプラットフォームのエンディアンが使われます。 エンディアンを指定したい場合は、シンボルbig-endianもしくは little-endianendian引数に渡して下さい。

(実際には、単純なビッグ/リトル以外のエンディアンも存在します。 binary.io - バイナリI/Oの議論も参照してください。)

Function: write-block vec &optional oport start end endian

ユニフォームベクタvecの内容を「そのまま」oportに書き出します。 oportが省略された場合はカレント出力ポートが使われます。 省略可能な引数startendが与えられた場合は、 それらのインデックスの範囲が示すvecの内容のみが出力されます。 endに-1を渡してvecの最後を示すこともできます。 この手続きの返す値は未定義です。

s8vectoru8vector以外のユニフォームベクタを与えた場合、 read-block!と同じようにエンディアンの影響を受けることに注意して 下さい。u32vector中の数値#x01020304は、 endian引数によって バイトシーケンス#x01, #x02, #x03, #x04と なるかもしれませんし、#x04, #x03, #x02, #x01となるかもしれません。 endian引数のデフォルト値はプラットフォームによって異なります。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Shiro Kawai on November, 22 2009 using texi2html 1.78.