四捨五入の計算結果にズレが生じる動作

2024年3月23日テクニカルメモ

この記事では浮動小数点数フォーマット(D型)の四捨五入の計算結果がズレる動作について説明しています。

数値フォーマットの種類によって計算結果が異なる

浮動小数点数フォーマット(D型)では数値データを内部的に二進数で保持する持ち方であることが影響して、小数点以下の計算が含まれる場合に数値がズレてしまう場合があります。

数値がズレてしまう例です。
下のサンプルでは「INT((29/50)*100)」という演算をD型とP型の項目として保持しています。
「29/50 = 0.58」ですので、100倍にした場合の期待する結果は「58」となります。

サンプルプロシジャ

SET PAGE-NUM = NOLEAD
TABLE FILE CAR
 SUM
  COMPUTE COL1/D17 = INT((29/50)*100);
  COMPUTE COL2/P17 = INT((29/50)*100);
 BY COUNTRY NOPRINT
 WHERE RECORDLIMIT EQ 1
END

結果は以下の通りです。

COL1(D型)は「57」
COL2(P型)は「58」
となっていますので、D型の結果がズレています。

何故、浮動小数点数フォーマットだと四捨五入の結果がズレるのか?

説明が重複しますが、浮動小数点数は二進数で値を表現することが影響しています。
「浮動小数点数内部表現」といったキーワードで一般情報を調べるとヒントになるかと思いますが、本記事では一例をご紹介します。

0.58 を浮動小数点数(double)で表現した場合の内部値

浮動小数点数では、「符号部」「指数部」「仮想部」といった形で表現されます。
「0.58」は内部的に以下のように変換されています。

double(64bit) =符号部1bit指数部11bit仮数部52bit

0 01111111110 0010100011110101110000101000111101011100001010001111

仮数部に注目すると、以下のような規則で循環している形になっていることが分かります。

00101000111101011100 00101000111101011100 00101000111101011100

この循環を見ると仮数部の53bit目は「0」になりますが、53bit目が「0」の時に「切り捨て」となるため、四捨五入の結果がズレてしまいます。

数値フォーマットに悩んだら…

WebFOCUSではパック10進数(P型)があるため、これを利用してください。

P型やD型の違いについても WebFOCUS knowledge base の記事がありますので、検索してみてください。