Fortran 95 区間演算プログラミングリファレンス ホーム目次前ページへ次ページへ索引


第 1 章

f95 で区間演算を使用するには

f95 INTERVAL 型と区間演算サポート

区間演算は、数の区間を使って計算を行うためのシステムです。区間演算は常に可能なすべての結果値の組み合わせを含む区間を生成するため、区間アルゴリズムはきわめて困難な計算を実現するように開発されました。区間アプリケーションのより詳細な情報については、README の区間演算を参照してください。

区間演算の誕生以来、狭幅区間の結果を生成する区間アルゴリズムが開発され、区間言語をサポートするための構文と意味論が設計されてきました。しかし、市場で利用でき、サポートを受けられる区間コンパイラについてはあまり改善されていません。1 つの例 (M77 Minnesota FORTRAN 1977 標準バージョン第 1 版) を除いて、区間システムは、これまで、プリプロセッサ、C++ クラス、あるいは、Fortran 90 のモジュールを基につくられています。f95 で区間データのサポートをコンパイラに組み込んだ目的は次のとおりです。

Sun WorkShop 6 の f95 リリースでの区間サポートは、大幅に拡張されています。

f95 区間サポートの目的:実装品質

f95 における組み込みの区間サポートの目的は、プログラム開発者に、次のような機能を提供することで、商業ベースの区間解決ライブラリとアプリケーションの開発を活性化することです。

サポートと機能は、実装品質の構成要素です。このマニュアルでは、全体を通してさまざまな実装品質が説明されています。お客様からの改善提案も受け付けております。

高品質の区間コード

正しい区間サポートコンパイラは、任意の区間式の評価の結果として、可能なすべての結果値の組み合わせを含む区間を生成しなければなりません。可能なすべての結果値の組み合わせを含むという要件は、区間演算の包含の制約と呼ばれます。この包含の制約を満たせない失敗は内部的なエラーです。区間の包含の制約を満たせない隠れた(警告や文書を伴わない) エラーは、任意の区間計算システムで致命的なエラーとなります。この 1 つの制約を満たすことで、区間は新しい計算品質を提供します。

包含の制約が満たされれば、実装品質は、実行時間と区間幅の軸を持つ二次元の平面上の 1 つの点の位置で決まります。両軸上は小さい値ほど良いことになります。実行時間と区間幅間の関係はアプリケーションに依存しますが、実行時間と区間幅は、区間システム品質の明確な尺度となります。区間幅と実行時間は常に実行時に入手して利用できますから、区間アルゴリズムと実装システムの両方の正確性の測定は速度の測定と同様、難しいことではありません。

Sun WorkShop 6 のパフォーマンスプロファイリングツールは区間プログラムの調整に使用できます。しかし、f95 には、アルゴリズムが不要に区間幅を増大する可能性のある場所を特定するための区間固有のツールはありません。「コード開発ツール」で解説しているように、区間の dbx と大域的なプログラム検査 (GPC) のサポートが提供されています。区間固有のコード開発とデバッグツールの追加により、優れた実装品質が得られます。

狭幅区間の生成

すべての言語やコンパイラの実装品質の基準となる項目、たとえば速度や使いやすさは区間用のツールにも適用されます。

更に、有効な区間実装システムは、常に包含の制約を満たす一方で計算区間の幅を最小化するという実装品質の基準もあります。

区間の幅が狭いほど、それは「鋭い」と表現されます。所与の浮動小数点精度について、区間幅が狭いほど、生成される区間は鋭くなります。

f95 コンパイラにより生成される区間の幅については、次のことがあてはまります。

迅速に実行できる区間コード

コンパイラの最適化とハードウェアの命令サポートの提供により、区間演算が対応する REAL 浮動小数点よりも著しく低速になることはありません。f95 では、組み込みの区間演算子と算術関数の速度について、次のことがあてはまります。

使いやすい開発環境

Fortran の組み込みの区間データ型は区間コードの開発、テスト、実行に役立ちます。区間コードを分かりやすくする (読み書きしやすくする) ために、区間構文と意味論が Fortran に追加されています。最終的には、これらの機能がユーザーに受け入れられれば、将来の Fortran 規格に取り入れられることになります。

区間を Fortran への組み込みデータ型として導入することで、Fortran の適用可能なすべての構文と意味論がすぐに利用できるようになります。Sun WorkShop 6 の f95 は、以下のような Fortran 区間機能の拡張を含んでいます。

これらの機能とその他の組み込み機能に関する例とより詳細な情報については、コード例 1-11 からコード例 1-14 までの例と「組み込み区間関数」を参照してください。

第 2 章ではこれらの関数とその他の区間機能を解説しています。

f95 区間コードの記述

この節の例は、初めて区間に接するプログラマが基本を理解し、有用な区間コードをすぐに記述できるような内容となっています。これらの例を基にして変更したり実際に使ってみることをおすすめします。

本書のすべてのコード例は、次のディレクトリに含まれています。

 /opt/SUNWspro/examples/intervalmath/docExamples

各例の名前は「cen-m.f95」となっていますが、n は例の現れる章を、mは例の番号を表しています。また、次のディレクトリには、追加の区間例が含まれています。

 /opt/SUNWspro/examples/intervalmath/general

コマンド行オプション

f95 コマンド行に以下のコマンド行マクロを含めると、組み込みの INTERVAL データ型を認識し、区間式の処理を制御します。

組み込みの INTERVAL データ型がコンパイラにより認識されるためには、f95 のコマンド行で、-xia または -xinterval を入力する必要があります。

区間と関連するすべてのコマンド行オプションについては、「区間のコマンド行オプション」で解説しています。最大幅要求式と厳密式の処理については、「区間演算式」で解説しています。

コード例 1-1では、f95 の区間サポートを使用した最も簡単なコマンド行呼び出しを示しています。

Hello Interval World

別途明示的な解説がない限り、すべてのコード例は、-xia コマンド行オプションを使ってコンパイルできます。-xia コマンド行オプションは f95 に対する区間拡張を使用するために必要です。

コード例 1-1 は、区間用の「Hello world」です。

コード例 1-1   Hello Interval World

math% cat ce1-1.f95
PRINT *, "[2, 3] + [4, 5] = ", [2, 3] + [4, 5]    !  1 行目
END 
math% f95 -xia ce1-1.f95
math% a.out
 [2, 3] + [4, 5] =  [6.0,8.0]

コード例 1-1 では、並びによる出力を用いて、区間 [2, 3] と [4, 5] の名前付き合計を表示しています。

区間の宣言と初期化

区間宣言文は、REALINTEGERCOMPLEX の宣言がそれぞれのデータ型に対して行うのと同じ機能を区間データ項目に対して実現します。区間のデフォルト種別型パラメータ値 (KTPV) は、INTEGER のデフォルトの KTPV の 2 倍です。これにより、任意のデフォルト INTEGER を縮退したデフォルトの区間を使って正確に表現できるようになります。より詳細な情報については、「デフォルトの種別型パラメータ値 (KTPV)」を参照してください。

コード例 1-2 は、区間変数と初期化を使用して、コード例 1-1 と同じことを実現しています。

コード例 1-2   区間変数を使用した Hello Interval World

math% cat ce1-2.f95
INTERVAL :: X = [2, 3], Y = [4, 5]   ! Line 1 
PRINT *, "[2, 3] + [4, 5] = ", X+Y   ! Line 2 
END
math% f95 -xia ce1-2.f95
math% a.out
 [2, 3] + [4, 5] =  [6.0,8.0]

1 行目では、変数 X と Y をデフォルト型の区間変数と宣言し、それぞれを [2, 3] と [4, 5] に初期化しています。第 2 行目では、並びによる出力を使って、名前付き区間 XY の合計を表示しています。

区間の入出力

区間の読み取りと書き出し用には完全なサポートが提供されます。区間と COMPLEX データ項目の読み取りと書き出しは類似しています。区間は囲み記号として丸括弧でなく角括弧を用います。区間データの読み取りと対話形式の入力は冗長になるので単数区間形式が導入されています。単数変換とは、角括弧に含まれない任意の数が、最後の表示桁に 1 単位を加算、減算して下限と上限が構築される 1 つの区間として翻訳されることです。

そこで、

2.345 = [2.344, 2.346],
2.34500 = [2.34499, 2.34501],

23 = [22, 24].

記号を用いると次のように表されます。

[2.34499, 2.34501] = 2.34500 + [-1, +1]uld

ここでは、[-1, +1]uld は、先行する数の最後の桁に区間 [-1, +1] が追加されることを意味します。添字 uld は、「最終桁の単位」(unit in the last digit) のニーモニックです。

縮退した区間を表すには、単一の数を角括弧で囲むことができます。たとえば次のように表されます。

[2.345] = [2.345, 2.345] = 2.345000000000.....

この変換は、入力と Fortran コードの縮退したリテラルな区間定数の両方に用います。このため、入力値を示す型 [0.1] は、0.1 をマシンが表現できない場合でも、1 つの正確な十進小数となります。

たとえば、プログラムに入力中の [0.1,0.1] = [0.1] は、点 0.1 を表しますが、単数入出力用法での 0.1 は、次のような区間を表します。

0.1 + [-1, +1]uld = [0, 0.2].

f95 では、入力変換処理は入力小数値を含む 1 つの鋭い区間を構築します。その値がマシンで表現できる場合は、内部的なマシン近似値は縮退しています。その値がマシンで表現できない場合は、1-ulp (仮数部の最終位置の単位) の幅を持つ区間が構築されます。


注 - uld と ulp は異なります。uld は最終表示桁に対する 1 単位の加減算を行うために、暗黙に、単数入出力形式を用いて区間を構築することを意味します。ulpは内部的なマシン数に与えることのできる最小の可能なインクリメントまたはデクリメントです。

区間データ項目を読み取ったり、印刷する最も簡単な方法は、並びによる入出力を使うことです。

コード例 1-3 は、ユーザーが並びによる READPRINT 文を使った区間演算と単数区間入出力を理解するのを支援する簡単なツールです。区間の書式化入出力については、「入力と出力」で記述しているように、完全なサポートが提供されています。


注意 - 区間の包含の制約は、入力中と出力中の両方で、丸めを使うことを必要としています。単数入力の直後で単数が出力されると、小数桁精度が失われることになります。実際に、入力値がマシン表現できない場合、入力区間幅は最大で 1-ulp だけ増えます。「単数の入出力」コード例 1-6 を参照してください。

コード例 1-3   区間の入出力

math% cat ce1-3.f95
   INTERVAL ::  X, Y
   INTEGER  :: IOS = 0
   PRINT *, "Press Control/D to terminate!"
   WRITE(*, 1, ADVANCE = 'NO')
   READ(*, *, IOSTAT = IOS) X, Y
   DO WHILE (IOS >= 0)
       PRINT *, " For X =", X, ", and Y =", Y
       PRINT *, "X+Y =", X+Y
       PRINT *, "X-Y =", X-Y
       PRINT *, "X*Y =", X*Y
       PRINT *, "X/Y =", X/Y
       PRINT *, "X**Y =", X**Y
       WRITE(*, 1, ADVANCE = 'NO')
       READ(*, *, IOSTAT=IOS) X, Y
   END DO
1  FORMAT(" X, Y = ? ") 
   END
%math f95 -xia ce1-3.f95
%math a.out
 Press Control/D to terminate!
 X, Y = ? [1,2] [3,4]
 For X = [1.0,2.0] , and Y = [3.0,4.0]
 X+Y = [4.0,6.0]
 X-Y = [-3.0,-1.0]
 X*Y = [3.0,8.0]
 X/Y = [0.25,0.66666666666666675]
 X**Y = [1.0,16.0]
 X, Y = ? [1,2] -inf
 For X = [1.0,2.0] , and Y = [-Inf,-1.7976931348623157E+308]
 X+Y = [-Inf,-1.7976931348623155E+308]
 X-Y = [1.7976931348623157E+308,Inf]
 X*Y = [-Inf,-1.7976931348623157E+308]
 X/Y = [-1.1125369292536012E-308,0.0E+0]
 X**Y = [0.0E+0,Inf] 
 X, Y = ? <Control-D>

単数の入出力

区間出力を読み取る際には、区間の最大下限と最小上限を比較して一致する桁数を数えることは手間のかかる作業の一つです。たとえば、コード例 1-4コード例 1-5 は、いろいろな幅を持つランダムな区間データを生成します。


注 - コード例 1-4コード例 1-5 では、プログラムの出力だけを示しています。この出力を生成するコードは、/opt/SUNWspro/examples/intervalmath/docExamples ディレクトリの例に含まれています。

コード例 1-4   [inf,sup] 区間出力

math%cat ce1-4.f95
%math f95 -xia ce1-4.f95
%math a.out
Press Control/D to terminate!
Enter number of intervals, KTPV (4,8,16) and 1 for single-number 
output: 5,4,0
[ 0.2017321E-029, 0.2017343E-029]
[ 0.2176913E-022, 0.2179092E-022]
[-0.3602303E-006,-0.3602302E-006]
[-0.3816341E+038,-0.3816302E+038]
[-0.1011276E-039,-0.1011261E-039]
Enter number of intervals, KTPV (4,8,16) and 1 for single-number 
output: 5,8,0
[ -0.3945547546440221E+035, -0.3945543600894656E+035]
[  0.5054960140922359E-270,  0.5054960140927415E-270]
[ -0.2461623589326215E-043, -0.2461623343163864E-043]
[ -0.2128913523672577E+204, -0.2128913523672576E+204]
[ -0.3765492464030608E-072, -0.3765492464030606E-072]
Enter number of intervals, KTPV (4,8,16) and 1 for single-number 
output: 5,16,0
[  0.199050353252318620256245071374058E+055,  
0.199050353252320610759742664557447E+055]
[ -0.277386431989417915223682516437493E+203, 
-0.277386431989417915195943874118822E+203]
[  0.132585288598265472316856821380503E+410,  
0.132585288598265472316856822706356E+410]
[  0.955714436647437881071727891682804E+351,  
0.955714436647437881071727891683760E+351]
[ -0.224211897768824210398306994401732E+196, 
-0.224211897768824210398306994177519E+196]
Enter number of intervals, KTPV (4,8,16) and 1 for single-number 
output: <Control-D>

コード例 1-4 の出力の読みやすさをコード例 1-5 のものと比較してみてください。

コード例 1-5   単数出力

%math a.out
 Press Control/D to terminate!
Enter number of intervals, KTPV (4,8,16) and 1 for single-number 
output: 5,4,1
     0.20173  E-029 
     0.218    E-022 
    -0.3602303E-006 
    -0.38163  E+038 
    -0.10112  E-039 
Enter number of intervals, KTPV (4,8,16) and 1 for single-number 
output: 5,8,1
     -0.394554          E+035 
      0.505496014092    E-270 
     -0.2461623         E-043 
     -0.2128913523672577E+204 
     -0.3765492464030607E-072 
Enter number of intervals, KTPV (4,8,16) and 1 for single-number 
output: 5,16,1
         0.19905035325232                   E+055 
        -0.2773864319894179152              E+203 
         0.132585288598265472316856822      E+410 
         0.955714436647437881071727891683   E+351 
        -0.224211897768824210398306994      E+196 
Enter number of intervals, KTPV (4,8,16) and 1 for single-number 
output: <Control-D>

単数表示形式では、後続のゼロが意味を持ちます。より詳細な情報については、「入力と出力」を参照してください。

区間は、伝統的な [inf, sup] 表示形式を使って、常に入力、表示することができます。また、角括弧で囲まれた単数は点を表します。たとえば、[0.1] の入力は、1/10 に翻訳されます。包含を保証するために、丸めによる方法を使って、1/10 の数を含むことがわかっている区間の近似値が構築されます。

コード例 1-6   内部データ変換を伴う文字入力

math% cat ce1-6.f95
INTERVAL :: X
   INTEGER  :: IOS = 0
   CHARACTER*30 BUFFER
   PRINT *, "Press Control/D to terminate!"
   WRITE(*, 1, ADVANCE='NO')
   READ(*, '(A12)', IOSTAT=IOS) BUFFER 
   DO WHILE (IOS >= 0)
     PRINT *, ' Your input was: ', BUFFER
     READ(BUFFER, '(Y12.16)') X
     PRINT *, "Resulting stored interval is:", X
     PRINT '(A, Y12.2)', ' Single number interval output  is:', X 
     WRITE(*, 1, ADVANCE='NO')
     READ(*, '(A12)', IOSTAT=IOS) BUFFER 
   END DO
1  FORMAT(" X = ? ")
   END
math% f95 -xia ce1-6.f95
math% a.out
 Press Control/D to terminate!
 X = ? 1.37
 入力値: 1.37                          
 Resulting stored interval is:  
[1.3599999999999998,1.3800000000000002]
 Single number interval output  is:  1.3       
 X = ? 1.444
 Your input was: 1.444                         
 Resulting stored interval is:  
[1.4429999999999998,1.4450000000000001]
 Single number interval output  is:  1.44      
 X = ? <Control-D>

コード例 1-6 注記:

区間の文と式

f95 コンパイラには以下のような区間固有の文、式、拡張が含まれます。

デフォルトの種別型パラメータ値 (KTPV)

表 1-1   区間固有の文と式

文または式 解説
INTERVAL
INTERVAL(4)
INTERVAL(8)
INTERVAL(16)
デフォルトの INTERVAL 型宣言
KIND=4INTERVAL
KIND=8INTERVAL
KIND=16INTERVAL
[a,b](1)
INTERVAL 文字定数: [a,b] 
[a](2)
[a,a]
INTERVAL A
PARAMETER A=[c,d] 

名前付き定数: A
V = expr (3)
値の代入
FORMAT(E, EN, ES, F, G, VE, VF, VG, 
VEN, VES, Y)(4)
E, EN, ES, F, G, VE, VF, VG, 
VEN, VES, Y 編集記述子
(1) 文字 ab は、0.10.2 のような小数文字定数可変部分が入ります。

(2) 角括弧内部の単一の小数定数は縮退した区間定数を表します。入出力でも同様です。

(3) expr が、INTERVAL 型の項目を含むかどうかにかかわらず、任意の Fortran 算術式を表すものとします。V = expr の代入文は式 expr を評価しその結果の値を V に代入します。-xia=strict コマンド行オプションのもとでは、混合モードの区間式は使用できません。-xia、または、-xia=widestneed オプションのもとでは、混合モード式は最大幅要求式処理を使って正しく評価されます。最大幅要求のもとでは、式評価の前に、すべての整数と浮動小数点データ項目は、V を含む式の中で使われている最大の KTPV を持つ区間を含むよう昇格されます。詳細については、「値の代入」を参照してください。

(4) 区間の入出力サポートは、柔軟性、可読性、開発の容易性を提供するよう設計されています。最も重要な新しい編集記述子は Y ですが、この記述子は単数区間形式を使って区間を読み、表示するために用いられます。区間を処理できるすべての記述子の完全な説明については、「入力と出力」を参照してください。


f95 では、デフォルトの INTEGER KTPV は、KIND(0) = 4 です。縮退したデフォルトの区間を使って任意のデフォルト INTEGER を表すためには、デフォルトの区間 KTPV である KIND([0]) が、2*KIND(0) = 8 である必要があります。これは次の理由によります。

値の代入 V = expr

区間の代入文は、可変部分 expr で表される区間式の値を、区間変数、配列要素、あるいは、配列としての V に代入します。構文は次のとおりです。

 V = expr

V は、INTERVAL 型を持たなければならず、また、expr は任意の非 COMPLEX の数式を表します。最大幅要求式処理のもとでは、式 expr は、区間式である必要はありません。厳密式処理のもとでは、expr は、V と同じ KTPV を使った区間式でなければなりません。

混合型式の評価

混合型の区間式を有効に使用することは、明確な (理解しやすい) 算術式の記述に役立つので、重要で使いやすい機能です。

混合型の区間式は、区間コードの記述と読みを REAL コードと同じように使いやすくするためにサポートされています。区間の包含の制約は、最大幅要求または厳密のいずれかの式処理を用いた混合モード式で満たされます。

最大幅要求式処理と厳密式処理

区間定数の幅が、「区間演算式」で解説しているように、式の文脈により動的に定義されている場合には、狭幅区間結果の計算が役立ちます。コード例 1-7 で示しているように、KTPV 混合式の中では、動的に増加する区間変数の KTPV が区間式結果の幅を減少させることもあります。

コード例 1-7   最大幅要求を用いた混合精度

math% cat ce1-7.f95
INTERVAL(4) :: X = [1, 2], Y = [3, 4]
INTERVAL    :: Z1, Z2

 
! 最大幅要求コード
Z1 = X*Y                                        ! 3 行目

 
! 同等の厳密コード
Z2 = INTERVAL(X, KIND=8)*INTERVAL(Y, KIND=8)    ! 4 行目
IF (Z1 .SEQ. Z2)  PRINT *, 'Check.'
END
math% f95 -xia ce1-7.f95
math% a.out
 Check.

3 行目では、KTPVmax = KIND(Z) = 8 となります。この値は、積の計算前に、XY の KTPV を 8 へと昇格させ、結果を Z1 に格納するのに使用されます。

これらの手順は、4 行目の同等の厳密コードの中で明示的に示されています。

文を走査して最大 KTPV を決定し必要な昇格を実行するプロセスは、最大幅要求式処理とよばれます。「区間演算式」を参照してください。

区間構成子の構文と意味論については、「組み込み区間演算子の拡張」を参照してください。

(型と KTPV の) 混合モード式

KTPV とデータ型と共に、最大幅要求の原則が用いられると、(型と KTPV の) 混合モード区間式が安全かつ予測的に評価できるようになります。たとえば、コード例 1-8 では、XY は区間変数なので、3 行目の Y1 の式は 1 つの区間式です。

コード例 1-8   最大幅要求を用いた型混合

math% cat ce1-8.f95
INTERVAL(16) :: X = [0.1, 0.3]
INTERVAL(4)  :: Y1, Y2

 
! 最大幅要求コード
 Y1 = X + 0.1                               ! 3 行目

 
! 同等の厳密コード   
 Y2 = INTERVAL(X + [0.1_16], KIND=4)        ! 4 行目
 IF (Y1 == Y2) PRINT *, "Check."
END
 
math% f95 -xia ce1-8.f95
math% a.out
 Check.

包含を保証するためには、定数 0.1 に対する実近似値の代わりに内部的な区間が使用されなければなりません。しかし、KIND(X) = 16 なので、KTPVmax = 16 となります。このため、X の更新には、正確な値 1/10 を含む鋭い KTPV = 16 区間である区間定数 [0.1_16] が使用されます。最後に、この結果が区間を含む KTPV = 4 へと変換され、Y に代入されます。4 行目は同等の厳密コードを含んでいます。厳密式処理のもとでは、混合型または混合 KTPV の式はどちらも許可されません。

最大幅要求式処理の論理的な手順は次のようになります。

1. 左側を含む文全体を走査して、任意の区間データ項目を求めます。

INTERVAL 型の定数、変数、または、組み込み関数があると、式の型は INTERVAL になります。

2. 区間式を走査して、各 INTERVALREALINTEGER、定数、または変数の KTPV にもとづき、KTPVmax を求めます。


注 - 整数は 2 倍の KTPV を持つ区間に変換されるので、すべての整数値は正確に表現できます。

3. すべての変数と定数を KTPVmaxを持つ区間に昇格させます。

4. 式を評価します。

5. 左側の KTPV に一致させる必要があれば、結果をより低い KTPV へと変換します。

6. 生成された値を左側に代入します。

これらの手順は、混合モードの区間式処理が包含の制約を満たし、効果的に合理的な狭い区間結果を生成することを保証します。

最大幅要求式処理を使った混合モードの区間式の評価は、-xia コマンド行フラグを使ったデフォルトでサポートされます。-xia=strict を使うと、区間への任意の自動的な型変換と任意の区間変数の自動的な KTPV の増加を行いません。厳密モードでは、すべての区間型と精度の変換が明示的にコード化されなければなりません。

演算式

区間データ項目を含む算術式の記述は、簡単で直接的です。区間文字定数と組み込みの区間固有の関数を除けば、区間式は REAL 算術式のように見えます。特に、最大幅要求式処理では、REALINTEGER 変数と文字定数は、コード例 1-9 で示しているように、区間式の中のどこででも自由に使用することができます。

コード例 1-9   簡単な区間式の例

math% cat ce1-9.f95
INTEGER  :: N = 3
REAL     :: A = 5.0                  
INTERVAL :: X

 
X = 0.1*A/N                     ! 5 行目
PRINT *, "0.1*A/N = ", X
END

 
math% f95 -xia ce1-9.f95
math% a.out
 0.1*A/N =  [0.16666666666666662,0.16666666666666672]

5 行目で代入が行われる変数 X は 1 つの区間ですから、式 0.1 * A/N の評価の前に、次の手順が実行されます。

1. 文字定数 0.1 は、縮退した区間 [0.1] を含むデフォルトの区間変数へと変換されます。

規格に沿った区間システムの実装での要件ではありませんが、Sun WorkShop 6 の f95 は鋭いデータ変換を実行します。たとえば、区間の近似値 [0.1] は 1-ulp の幅となります。

2. REAL 変数 A は、縮退した区間 [5] に変換されます。

3. INTEGER 変数 N は、縮退した区間 [3] に変換されます。

式 [0.1]×[5]/[3] は、区間演算を使用して評価されます。上記手順は最大幅要求式処理の一部であり、これは、混合モードの区間式の評価時の包含の制約を満たすために必要です。「混合型式の評価」を参照してください。

区間代入文は、代入先の変数が区間変数、配列要素または配列でなければならないという 1 つの要件を満たさなければなりません。最大幅要求処理モードに関する詳細情報については、「混合モードの区間式」を参照してください。

Sun WorkShop 6 の f95 で実装された区間システムは閉鎖型ですから、任意の区間式が有効な区間結果の生成に失敗すれば、コンパイラエラーとして表示されます。疑わしいエラーの表示方法については、「コード開発ツール」を、既知のエラーの一覧については、「既知の内部的なエラー」をそれぞれ参照してください。


注 - 算術的に同等の区間式が常に同じ幅を持つ区間を生成するわけではありません。また、単一の区間式を評価するだけでは鋭い結果を計算できないことがよくあります。一般的に、区間の結果としての幅は、区間引数の値と式の形式に依存します。

区間の順位関係

区間の順位付けは点の順位付けよりも複雑です。2 が 3 よりも小さいことをテストするのはあいまいなことではありません。区間を使用すると、区間 [2,3] は区間 [4,5] よりも小さいことになりますが、区間 [2,3][3,4] の場合はどのように表現すべきなのでしょう?

区間関係演算子としては、以下の 3 つの異なるクラスが実装されています。

断定的な関係が true となるためには、オペランド区間のすべての要素がその関係を満たさなければなりません。オペランド区間の任意の要素によりその関係が満たされると、可能性のある関係は true となります。集合の関係は、区間を集合として取り扱います。区間関係演算子のこれらの 3 つのクラスは、両方のオペランド区間が共に縮退すると、点に関する通常の関係演算子に収束します。

3 つの演算子クラスを区別するために、通常の 2 文字で表す Fortran のニーモニックには、CP、または、S 文字の接頭辞を付けます。f95 では、集合演算子 .SEQ..SNE. は、点型のデフォルト (.EQ. または==、と、.NE. または/=) がサポートされる唯一の演算子となっています。その他のすべてのケースでは、次の例のように、関係演算子クラスが明示的に識別されなければなりません。

すべての区間演算子の構文と意味論については、「組み込み演算子」を参照してください。

次のプログラムは、「集合の関係」での等式テストを示しています。

コード例 1-10   集合等式テスト

math% cat ce1-10.f95
INTERVAL :: X = [2, 3], Y = [4, 5]        ! 1 行目 
IF(X+Y .SEQ. [6, 8]) PRINT *, "Check."    ! 2 行目
END
math% f95 -xia ce1-10.f95
math% a.out
 Check.

2 行目では、集合の関係の等式テストを使って、X+Y が区間 [6, 8] に等しいことを検証しています。

次の記述は、2 行目のものと同等です。

 IF(X+Y == [6, 8]) PRINT *, "Check." ! 2 行目 

区間固有の関係演算子の結果を試してみる場合は、コード例 1-11コード例 1-12 を使ってください。

コード例 1-11   区間関係演算子

math% cat ce1-11.f95
   INTERVAL ::  X, Y
   INTEGER  :: IOS = 0
   PRINT *, "Press Control/D to terminate!"
   WRITE(*, 1, ADVANCE='NO')
   READ(*, *, IOSTAT=IOS) X, Y
   DO WHILE (IOS >= 0)
       PRINT *, " For X =", X, ", and Y =", Y
       PRINT *, 'X .CEQ. Y, X .PEQ. Y, X .SEQ. Y =', &
                 X .CEQ. Y, X .PEQ. Y, X .SEQ. Y    
       PRINT *, 'X .CNE. Y, X .PNE. Y, X .SNE. Y =', &
                 X .CNE. Y, X .PNE. Y, X .SNE. Y    
       PRINT *, 'X .CLE. Y, X .PLE. Y, X .SLE. Y =', &
                 X .CLE. Y, X .PLE. Y, X .SLE. Y    
       PRINT *, 'X .CLT. Y, X .PLT. Y, X .SLT. Y =', &
                 X .CLT. Y, X .PLT. Y, X .SLT. Y    
       PRINT *, 'X .CGE. Y, X .PGE. Y, X .SGE. Y =', &
                 X .CGE. Y, X .PGE. Y, X .SGE. Y    
       PRINT *, 'X .CGT. Y, X .PGT. Y, X .SGT. Y =', &
                 X .CGT. Y, X .PGT. Y, X .SGT. Y
       WRITE(*, 1, ADVANCE='NO')
       READ(*, *, IOSTAT=IOS) X, Y
   END DO
1  FORMAT( " X, Y = ")
   END
math% f95 -xia ce1-11.f95
math% a.out
 Press Control/D to terminate!
 X, Y = [2] [3]
 For X = [2.0,2.0] , and Y = [3.0,3.0]
 X .CEQ. Y, X .PEQ. Y, X .SEQ. Y = F F F
 X .CNE. Y, X .PNE. Y, X .SNE. Y = T T T
 X .CLE. Y, X .PLE. Y, X .SLE. Y = T T T
 X .CLT. Y, X .PLT. Y, X .SLT. Y = T T T
 X .CGE. Y, X .PGE. Y, X .SGE. Y = F F F
 X .CGT. Y, X .PGT. Y, X .SGT. Y = F F F
 X, Y = 2 3
 For X = [1.0,3.0] , and Y = [2.0,4.0]
 X .CEQ. Y, X .PEQ. Y, X .SEQ. Y = F T F
 X .CNE. Y, X .PNE. Y, X .SNE. Y = F T T
 X .CLE. Y, X .PLE. Y, X .SLE. Y = F T T
 X .CLT. Y, X .PLT. Y, X .SLT. Y = F T T
 X .CGE. Y, X .PGE. Y, X .SGE. Y = F T F
 X .CGT. Y, X .PGT. Y, X .SGT. Y = F T F
 X, Y = <Control-D>

コード例 1-12 は、表 1-2 に掲載した区間固有の演算子用法を例示しています。

表 1-2   区間固有の演算子

演算子 名前 算術記号
.IH.
区間包
.IX.
積集合
.DJ.
.IN.
要素
.INT.
内部 「内部:(X .INT. Y)KAKKOEを参照してください。
.PSB.
真部分集合
.PSP.
真超集合
.SB.
部分集合
.SP.
超集合


コード例 1-12    集合演算子

math% cat ce1-12.f95
   INTERVAL ::  X, Y
   INTEGER  :: IOS = 0
   REAL(8)  :: R = 1.5
 PRINT *, "Press Control/D to terminate!"
   WRITE(*, 1, ADVANCE='NO')
   READ(*, *, IOSTAT=IOS) X, Y
   DO WHILE (IOS >= 0)
       PRINT *, " For X =", X, ", and Y =", Y
       PRINT *, 'X .IH.  Y =', X .IH. Y
       PRINT *, 'X .IX.  Y =', X .IX. Y
       PRINT *, 'X .DJ.  Y =', X .DJ. Y
       PRINT *, 'R .IN.  Y =', R .IN. Y
       PRINT *, 'X .INT. Y =', X .INT. Y
       PRINT *, 'X .PSB. Y =', X .PSB. Y
       PRINT *, 'X .PSP. Y =', X .PSP. Y
       PRINT *, 'X .SP.  Y =', X .SP. Y
       PRINT *, 'X .SB.  Y =', X .SB. Y

       WRITE(*, 1, ADVANCE='NO')
       READ(*, *, IOSTAT=IOS) X, Y
   END DO
1  FORMAT(" X, Y = ? ")
   END
math% f95 -xia ce1-12.f95
math% a.out
 Press Control/D to terminate!
 X, Y = ? [1] [2]
 For X = [1.0,1.0] , and Y = [2.0,2.0]
 X .IH.  Y = [1.0,2.0]
 X .IX.  Y = [EMPTY]
 X .DJ.  Y = T
 R .IN.  Y = F
 X .INT. Y = F
 X .PSB. Y = F
 X .PSP. Y = F
 X .SP.  Y = F
 X .SB.  Y = F
 X, Y = ? [1,2] [1,3]
 For X = [1.0,2.0] , and Y = [1.0,3.0]
 X .IH.  Y = [1.0,3.0]
 X .IX.  Y = [1.0,2.0]
 X .DJ.  Y = F
 R .IN.  Y = T
 X .INT. Y = F
 X .PSB. Y = T
 X .PSP. Y = F
 X .SP.  Y = F
 X .SB.  Y = T
 X, Y = ? <Control-D>

組み込みの区間固有の関数

組み込みの区間固有の関数としてさまざまなものが提供されています。「組み込み関数」を参照してください。コード例 1-13 を使うと、組み込みの区間固有の関数の動作を調べることができます。

コード例 1-13   組み込みの区間固有の関数

math% cat ce1-13.f95
   INTERVAL ::  X, Y
   PRINT *, "Press Control/D to terminate!"
   WRITE(*, 1, ADVANCE='NO')
   READ(*, *, IOSTAT=IOS) X
   DO WHILE (IOS >= 0)
       PRINT *, " For X =", X
       PRINT *, 'MID(X)= ', MID(X)
       PRINT *, 'MIG(X)= ', MIG(X)
       PRINT *, 'MAG(X)= ', MAG(X)
       PRINT *, 'WID(X)= ', WID(X)
       PRINT *, 'NDIGITS(X)= ', NDIGITS(X)
       WRITE(*, 1, ADVANCE='NO')
       READ(*, *, IOSTAT=IOS) X
   END DO
1  FORMAT(" X = ?")
   END
math% f95 -xia ce1-13.f95
math% a.out 
 Press Control/D to terminate!
 X = ?[1.23456,1.234567890]
 For X = [1.2345599999999998,1.2345678900000002]
 MID(X)=  1.234563945
 MIG(X)=  1.2345599999999998
 MAG(X)=  1.2345678900000001
 WID(X)=  7.890000000232433E-6
 NDIGITS(X)=  6
 X = ?[1,10]
 For X = [1.0,10.0]
 MID(X)=  5.5
 MIG(X)=  1.0
 MAG(X)=  10.0
 WID(X)=  9.0
 NDIGITS(X)=  1
 X = ? <Control-D>

標準組み込み関数の区間バージョン

Fortran の REAL 引数を受け入れるすべての組み込み関数は、区間バージョンを持っています。「組み込み関数」を参照してください。コード例 1-14 を使用すると、いくつかの組み込み関数の動作を調べることができます。

コード例 1-14   標準組み込み関数の区間バージョン

math% cat ce1-14.f95
   INTERVAL :: X, Y
   INTEGER  :: IOS = 0
   PRINT *, "Press Control/D to terminate!"
   WRITE(*, 1, ADVANCE='NO')
   READ(*, *, IOSTAT=IOS) X
   DO WHILE (ios >= 0)
      PRINT *, "For X =", X
      PRINT *, 'ABS(X) = ', ABS(X)
      PRINT *, 'LOG(X) = ', LOG(X)
      PRINT *, 'SQRT(X)= ', SQRT(X)
      PRINT *, 'SIN(X) = ', SIN(X)
      PRINT *, 'ACOS(X)= ', ACOS(X)
      WRITE(*, 1, ADVANCE='NO')
      READ(*, *, IOSTAT=IOS) X
   END DO
1  FORMAT(" X = ?")
   END
math% f95 -xia ce1-14.f95
math% a.out
 Press Control/D to terminate!
 X = ?[1.1,1.2]
For X = [1.0999999999999998,1.2000000000000002]
 ABS(X) =  [1.0999999999999998,1.2000000000000002]
 LOG(X) =  [0.095310179804324726,0.18232155679395479]
 SQRT(X)=  [1.0488088481701514,1.0954451150103324]
 SIN(X) =  [0.89120736006143519,0.93203908596722652]
 ACOS(X)=  [EMPTY]
 X = ?[-0.5,0.5]
For X = [-0.5,0.5]
 ABS(X) =  [0.0E+0,0.5]
 LOG(X) =  [-Inf,-0.69314718055994528]
 SQRT(X)=  [0.0E+0,0.70710678118654758]
 SIN(X) =  [-0.47942553860420307,0.47942553860420307]
 ACOS(X)=  [1.0471975511965976,2.0943951023931958]
 X = ? <Control-D>

コード開発ツール

区間コード開発に関する情報はオンラインで利用できます。区間の Web サイト一覧とその他のオンラインのリソースについては、区間演算の README を参照してください。

疑わしい区間エラーを報告される場合は、次の宛先に電子メールをお送りください。

sun-dp-comments@Sun.com

主題の行か本文中に次のテキストを含めてください。

WORKSHOP "6.0 mm/dd/yy" Interval

ここでは、mm/dd/yy は、月、日、年度を表します。

デバッグのサポート

Sun Workshop 6 では、区間データ型は dbx により次に示す範囲でサポートされます。

dbx 機能に関する追加的な詳細については、「dbx コマンドによるデバッグ」を参照してください。

大域的なプログラム検査

Sun WorkShop 6 の Fortran 95 における大域的なプログラム検査 (GPC) は、1 つの区間固有のエラーとして、ユーザー供給ルーチン呼び出しでの INTERVAL 型の不一致を検出します。

コード例 1-15   INTERVAL 型の不一致

math% cat ce1-15.f95
INTERVAL X
X = [-1.0,+2.9]
PRINT *,X
CALL SUB(X)
END
SUBROUTINE SUB(Y)
INTEGER Y(2)
PRINT *,Y
END
math% f95 -xia ce1-15.f95 -Xlist

 
--- ce1-15.lst を参照 ---

 
              Global Call-Chain Considerata
             ===============================

 
     1) <503>  At line 4, MainPgm() calls SUB(fileline 6):
        MainPgm() sends argument 1 as type "Interval(16),"
        but SUB() expects type "Integer(4)"

 
     2) <507>  At line 4, MainPgm() calls SUB(fileline 6):
        MainPgm() sends argument 1 as a "Scalar,"
        but SUB() expects a "1-D Array"

Sun Fortran ライブラリで提供される区間機能

次のライブラリには区間の組み込みルーチンがあります。

表 1-3   区間ライブラリ
ライブラリ 名前 必要なオプション
区間組み込み配列関数 libifai なし
区間組み込みライブラリ libsunimath なし


コードの移植とバイナリファイル

使用上対処の必要な、制限のある古い区間 Fortran コードが存在します。言語の構文と意味論が標準化されるまでは、異なる区間コンパイラ供給者のサポートが異なることは避けらません。お客様からの最も馴染みのある区間構文と意味論を考慮したフィードバックは標準化過程に役立ちます。区間演算の README に一覧表示された電子メールのエイリアスに、コメントを送付することもできます。

バイナリファイルでの区間の表現は、コンパイラがより狭い区間システムをサポートするかどうかにより異なります。

並列処理

このリリースでは、-autopar コンパイラオプションは区間算術演算を含むループ処理に効果がありません。これらのループ処理は自動的には並列処理されません。明示的な並列化指令を付したループの並列化には、-explicitpar コンパイラオプションを使用しなければなりません。

エラーの検出

次のコード例では、区間固有のエラーメッセージを一覧表示しています。各コード例にはエラーメッセージとエラーを生成したコードが含まれています。

コード例 1-16   無効な終了点

math% cat ce1-16.f95
INTERVAL :: I = [2., 1.] 
END
 
math% f95 -xia ce1-16.f95

 
INTERVAL :: I = [2., 1.] 
                       ^  
"ce1-14.f95", Line = 1, Column = 24: エラー:区間定数の左側の終了点は右
側の終了点以下でなければなりません。

 
f90: コンパイル時間 0.150000 SECONDS
f90: 最大フィールド長 4117346 10 進ワード
f90: 2 ソース行
f90: 1 個のエラー、0 個の警告、 0 個の他のメッセージ、 0 個のANSI

コード例 1-17   区間と非区間の同値

math% cat ce1-17.f95
INTERVAL :: I
REAL     :: R
EQUIVALENCE (I, R) 
END
 
math% f95 -xia ce1-17.f95

 
EQUIVALENCE (I, R) 
             ^      
"ce1-15.f95", Line = 3, Column = 14: エラー: INTERVAL 実体 "I" と 
REAL 実体 "R" の結合指定は許可されません。

 
f90: コンパイル時間 0.160000 SECONDS
f90: 最大フィールド長 4117346 10 進ワード
f90: 4 ソース行
f90: 1 個のエラー、0 個の警告、 0 個の他のメッセージ、 0 個のANSI

コード例 1-18   異なる KTPV を持つ区間オブジェクトの同値

math% cat ce1-18.f95
INTERVAL(4) :: I1
INTERVAL(8) :: I2
EQUIVALENCE (I1, I2) 
END
 
math% f95 -xia ce1-18.f95

 
EQUIVALENCE (I1, I2) 
             ^        
"ce1-16.f95", Line = 3, Column = 14: エラー: 異なる種別型パラメータを
持つ INTERVAL 実体 "I1" と "I2" の結合指定はできません。

 
f90: コンパイル時間 0.190000 SECONDS
f90: 最大フィールド長 4117346 10 進ワード
f90: 4 ソース行
f90: 1 個のエラー、0 個の警告、 0 個の他のメッセージ、 0 個のANSI

コード例 1-19    厳密モードでの区間変数への REAL 式の代入

math% cat ce1-19.f95
INTERVAL :: X
REAL     :: R
X = R
END
math% f95 -xia=strict ce1-19.f95

 
X = R
  ^   
"ce1-17.f95", Line = 3, Column = 3: エラー: REAL 式を INTERVAL 変数
へ代入することは許可されません。

 
f90: コンパイル時間 0.350000 SECONDS
f90: 最大フィールド長 4117346 10 進ワード
f90: 4 ソース行
f90: 1 個のエラー、0 個の警告、 0 個の他のメッセージ、 0 個のANSI

コード例 1-20   厳密モードでの区間変数への区間式の代入

math% cat ce1-20.f95
INTERVAL     :: X
INTERVAL(16) :: y
X = Y
END
math% f95 -xia=strict ce1-20.f95

 
X = Y
  ^   
"ce1-18.f95", Line = 3, Column = 3: エラー: INTERVAL 変数に対する 
INTERVAL 式の代入はそれらが異なる種別型パラメータを持つ場合、許可されません。

 
f90: コンパイル時間 0.170000 SECONDS
f90: 最大フィールド長 4117346 10 進ワード
f90: 4 ソース行
f90: 1 個のエラー、0 個の警告、 0 個の他のメッセージ、 0 個のANSI

既知の内部的なエラー

内部的なエラーが発生する可能性がある場合は常にコンパイル時の警告が出力される必要があります。このような警告が必要とされる状況は、最大幅要求式処理のスコープの外側で整数式を用いる場合です。

整数オーバーフロー

数の不正確性は、通常は INTEGER 式よりもむしろ REAL 式と関係します。しかしある意味では、INTEGER 式は REAL 式よりも危険です。REAL 式がオーバーフローすると例外が提起されて IEEE 無限大が生成されます。例外はオーバーフローが発生したという警告です。無限大は、浮動小数点計算で潜在的な問題があることをユーザーに知らせます。オーバーフロー発生時にそれをトラップすることもできます。

整数式がオーバーフローすると、それらは場合によっては、反対符号の値へと暗黙のうちに変換されてしまいます。さらに、逆の操作を実行して、すべての整数操作に関し同値テストを行うことが、整数式のオーバーフローの発生時期を検出する唯一の方法です。整数定数式の場合はコンパイル中に評価され、オーバーフローが検出されて警告メッセージが出力されるため安全です。

次の例は最大幅要求式処理のスコープが、INTEGER 指数を使った ** 演算を含む、すべての組み込みの INTEGER 演算と関数にまで拡張されると何が起きるのかを示しています。

コード例 1-21   INTEGER オーバーフローの内部的なエラー

math% cat ce1-21.f95
   INTERVAL :: X = [2], Y = [2]
   INTEGER  :: I = HUGE(0)
   X = X**(I+1)
   Y = Y*(Y**I)
   IF(X .DJ. Y) PRINT *, "X and Y are disjoint."
   END
math% f95 -xia ce1-21.f95
math% a.out
 X and Y are disjoint.

このコード例はメッセージを表示しない内部的なエラーを示しています。最大幅要求式処理のスコープは、現在のところ ** 演算の整数指数にまで及ばないので、これは既知のエラーです。べき乗演算子に関する情報については、「べき乗演算子 X**N と X**Y」を参照してください。


注意 - このエラーは、Sun WorkShop 6 の Fortran 95 リリースではまだ修正されていません。また、警告メッセージも出力されません。


サン・マイクロシステムズ株式会社
Copyright information. All rights reserved.
ホーム   |   目次   |   前ページへ   |   次ページへ   |   索引