4

AS/400 で COMPUTE 機能を使用しているときに、不可解な問題に直面しました。

シナリオは次のとおりです。

01  WSAA-AMOUNT-A               PIC S9(15)V9(02) COMP-3.
01  WSAA-AMOUNT-B-01            PIC S9(16)V9(02) VALUE 0.
01  WSAA-AMOUNT-B-02            PIC S9(13)V9(05) VALUE 0.
01  WSAA-AMOUNT-C               PIC S9(16)V9(02) VALUE 0.
01  WSAA-RESULT                 PIC S9(15)V9(02) VALUE 0.

MOVE 2500.87             TO WSAA-AMOUNT-A. 
MOVE 12285               TO WSAA-AMOUNT-B-01.
MOVE 12285               TO WSAA-AMOUNT-B-02.
MOVE 4387.5              TO WSAA-AMOUNT-C. 

COMPUTE WSAA-RESULT ROUNDED = (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-01 + WSAA-AMOUNT-C) * 100 ).
DISPLAY WSAA-RESULT.

COMPUTE WSAA-RESULT ROUNDED = (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-02 + WSAA-AMOUNT-C) * 100 ).
DISPLAY WSAA-RESULT.

結果は、最初の式の結果が = 14.90 であるのに対し、2 番目の式は = 15 になったことに驚きました。

後者の方が 2500.87 / (12285+4387.5) * 100 = 14.99997001 としてより論理的です。丸めた後、最初の結果の結果も15になるはずです。

これらの一貫性のない結果の根本的な原因を知っている人はいますか?

4

1 に答える 1

4

達成された結果は、14.90 と 15.00 でした。

COMPUTE の形式が正しくありません。100 を掛ける場合は、できるだけ早く実行してください。最後に実行すると、小数点以下 2 桁が消えるためです (100 で割るときは、最後に実行して、早い段階で有効桁数を失わないようにします)。

100だけに当てはまるわけではないので、考えてみてください。関係する値が何であれ、最初に乗算し、最後に除算します。最終的な回答で小数点以下 5 桁が必要でない限り、「正しい」回答を得るために小数点以下 5 桁のフィールドを使用する必要はまったくありません。

コンピュータは電卓やスプレッドシートではありません。小数点以下の桁数が多い他の結果ではなく、要求に応じて中間結果を使用します。使用するフィールドの小数点以下の桁数を使用して、小数点以下の精度を要求します。

何が起こっているのかを理解するための鍵の 1 つは、ファイン マニュアルです。もう一つは実験です。多くの場合、これは一般的な答えになります。

COMPUTE WSAA-RESULT ROUNDED = 
                  (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-01 + WSAA-AMOUNT-C) * 100 )

WSAA-RESULT を表示します。答えは 14.90 (14.90) です。

COMPUTE WSAA-RESULT = 
                  (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-01 + WSAA-AMOUNT-C) * 100 )

WSAA-RESULT を表示します。ROUNDED を削除することにより、答え 14.00 (14 ポイント ゼロ ゼロ) を取得します。

COMPUTE WSAA-RESULT ROUNDED = 
                  (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-02 + WSAA-AMOUNT-C) * 100 )

DISPLAY WSAA-RESULT は、小数点以下 5 桁を使用して 15.00 (15 ポイント ゼロゼロ) の「正しい」「期待される」回答を取得します。

最後に 100 を掛けたことを思い出してください。その前の値は 0.149 (小数点以下 3 桁)、0.14 (小数点以下 2 桁)、1​​4.99999n (小数点以下 6 桁) でした。 6番目は「n」のままにしました)。

小数点以下3桁、2桁、6桁があるのはなぜですか? 6 は B-02 によるもので (5 桁に加えて ROUNDED の場合は 1 で、ROUNDED を計算できるように必要な小数点以下の桁数が 1 増加します)、2 は B-01 によるものです (小数点以下 2 桁)。 ) 3つあるのはB-01とROUNDEDのせいです。

これは、3 つのバージョンで作り直された COMPUTE です。

COMPUTE WSAA-RESULT ROUNDED =  ( ( WSAA-AMOUNT-A * 100 )
                               / ( WSAA-AMOUNT-B-01 
                                 + WSAA-AMOUNT-C ) ) 

COMPUTE WSAA-RESULT         =  ( ( WSAA-AMOUNT-A * 100 )
                               / ( WSAA-AMOUNT-B-01 
                                 + WSAA-AMOUNT-C) ) 

COMPUTE WSAA-RESULT ROUNDED = ( ( WSAA-AMOUNT-A * 100 ) 
                              / ( WSAA-AMOUNT-B-02 
                                + WSAA-AMOUNT-C) ) 

結果は 15.00、14.99、15.00 です。

これは Enterprise Cobol を使用しています。OpenCobol は、おそらく文書化されているさまざまな中間結果を使用しているようです。

中間結果に関するエンタープライズ COBOL プログラミング ガイドは次のとおりです。

「中間結果に関するこの情報を理解するには、次の用語を理解する必要があります。... d 中間結果の小数点以下の桁数。 v 1 つまたは複数の最終結果フィールドに必要な小数点以下の桁数 v 除数または指数を除く、任意のオペランドに定義された小数点以下の最大桁数 v 外側の任意の関数オペランドの dmax"

"Operation ... Decimal places
+ or - ... d1 or d2, whichever is greater
* ... d1 + d2
/ ... (d2 - d1) or dmax, whichever is greater"

「誤った」例では、加算は小数点以下 2 桁 (加算では d1 と d2 の両方が 2)、除算は小数点以下 3 桁 (dmax は 3)、乗算は小数点以下 3 桁 (ROUNDED では 2 + 0 + 1) になります。 )。丸めが試行された後の最終的な答えは (100 による乗算により下位 2 つの小数が常にゼロであるため、決して機能しません)、小数点以下 2 桁に切り捨てられます。

ROUNDED B-01 の場合、dmax は 3 です (2 桁の結果フィールドと、丸め用の 1 桁)。通常の B-01 の場合、dmax は 2 です。ROUNDED B-02 の場合、dmax は 6 です。

間違っているのは、示されている例だけではないことに注意してください。問題の最初の例では ROUNDED は機能せず、有効な小数は常に 1 つ削除されるため、四捨五入前の答えが 10 分の 1 の場合にのみ正しい答えが得られます。これらの正解は、切り捨てのために同じになる 9 つのさらなる解答によってマスクされます。

常に効果的な COMPUTE を記述していれば、問題は発生しません。ROUNDED は、最終結果に対してのみ機能します。中間フィールドの ROUNDED が必要な場合は、それを個別に計算し、その結果を新しい計算で使用します。

計算が機能します。COMPUTE は電卓/スプレッドシートのようには機能しません。他の Cobol 動詞もそうではありません (関数ではなく動詞です)。意味を失わないように、COMPUTE の書き方を考えます。マニュアルを読んでください。実験。正しく理解されるまで繰り返します。

于 2013-01-13T00:37:29.870 に答える