質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

2884閲覧

Cで DBL_MAX - 1.0 の結果がDBL_MAXになってしまう

yama_da

総合スコア73

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

1グッド

1クリップ

投稿2016/07/09 16:33

Cで DBL_MAX-1.0 の値が欲しかったのですが、実際に実行してみると結果の値は DBL_MAX のままでした。
気になって下のコードで実験してみました。

C

1#include <stdio.h> 2#include <limits.h> 3#include <float.h> 4 5int main(void) { 6 7 printf("\n"); 8 9 double dm=DBL_MAX; 10 double r1,r2,r3,r4,r5; 11 12 r1= dm - 1.0 - dm; 13 r2= dm - 123.0 - dm; 14 r3= dm - 12345.0 - dm; 15 r4= dm - 1234567.0 - dm; 16 r5= dm - 123456789.0 - dm; 17 18 printf("r1 = %.5lf\n",r1); 19 printf("r2 = %.5lf\n",r2); 20 printf("r3 = %.5lf\n",r3); 21 printf("r4 = %.5lf\n",r4); 22 printf("r5 = %.5lf\n\n",r5); 23 24 25 26 27 float fm=FLT_MAX; 28 float s1,s2,s3,s4,s5; 29 30 s1= fm - 1.0 - fm; 31 s2= fm - 123.0 - fm; 32 s3= fm - 12345.0 - fm; 33 s4= fm - 1234567.0 - fm; 34 s5= fm - 123456789.0 - fm; 35 36 printf("s1 = %.5f\n",s1); 37 printf("s2 = %.5f\n",s2); 38 printf("s3 = %.5f\n",s3); 39 printf("s4 = %.5f\n",s4); 40 printf("s5 = %.5f\n\n",s5); 41 42 43 44 45 int im=INT_MAX; 46 int t1,t2,t3,t4,t5; 47 48 t1= im - 1.0 - im; 49 t2= im - 123.0 - im; 50 t3= im - 12345.0 - im; 51 t4= im - 1234567.0 - im; 52 t5= im - 123456789.0 - im; 53 54 printf("t1 = %d\n",t1); 55 printf("t2 = %d\n",t2); 56 printf("t3 = %d\n",t3); 57 printf("t4 = %d\n",t4); 58 printf("t5 = %d\n\n",t5); 59 60 return 0; 61} 62

ですが、結果は

r1 = 0.00000 r2 = 0.00000 r3 = 0.00000 r4 = 0.00000 r5 = 0.00000 s1 = 0.00000 s2 = 0.00000 s3 = 0.00000 s4 = 0.00000 s5 = 0.00000 t1 = -1 t2 = -123 t3 = -12345 t4 = -1234567 t5 = -123456789

となり、INT_MAXのとき以外は全く期待した値になってくれませんでした。なぜでしょうか?

コンパイラ:gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
エディタ :Emacs 24.3.1

mondaminZ👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

INT_MAXのとき以外は全く期待した値になってくれませんでした。なぜでしょうか?

端的に言えば、そういう仕様です。

floatdoubleなどの「浮動小数点数(型)」と、intなどの「整数(型)」の仕組みを理解する必要があります。それぞれの特徴だけを説明するなら、下記の通りです:

  • 浮動小数点数:実数値(整数や小数点以下を含む値)を 近似的に 表現できます。代わりに、絶対値が大きい値の場合は、その有効桁数が制限されます。
  • 整数:整数値厳密に 表現できます。代わりに、あまり広い値域を表現することはできません。

(コメントより) そうする必要があるのかどうかは抜きにして、DBL_MAXから1引いた値を得ることは不可能ということでしょうか?

数学的な意味で「DBL_MAXから1引いた値」は、double型として表現できません(存在しません)。最も近い値として DBL_MAX - 1.0 == DBL_MAX となってしまいます。

投稿2016/07/11 10:45

yohhoy

総合スコア6189

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yama_da

2016/07/13 03:51

回答ありがとうございます。 最初の問題は別の方法で解決出来ました。 また機会があればよろしくお願いします。
guest

0

DBL_MAXはだいたい1.7976931348623157e+308のように定義されています。これは、1.7976……×10の308乗のことで、全て数字で表すと309桁必要になります。

その値から1を引くというのはどういうことかというと、桁位置を合わせないといけませんから、1をe+308で表して、0.000……001e+308(0が308個)を引くということになります(実際には同様のことを2進数で処理しています)。しかしながら、doubleの精度はせいぜい10数桁程度なので、その桁数を遙かに上回る数の0が続くと、それは0とみなされてしまいます。
結果、1を引いたつもりでも実際には0を引いているのと同じになるのです。123456789でも0の数が308個から300個に減った程度で結果は同じです。

doubleに限らず、コンピューターで数値を扱う場合、精度(有効桁数)や内部的な仕組み(2進数表現)などを考慮しないと、思わぬ結果になることがままあります。

投稿2016/07/10 05:56

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yama_da

2016/07/13 03:53

回答ありがとうございます。 最初の問題は別の方法で解決出来ました。 また機会があればよろしくお願いします。
guest

0

ベストアンサー

こんにちは。

単純に桁落ちです。
doubleの指数部は11ビットで、仮数部が52ビットです。
DBL_MAXは 1.11111...(52ビット) * 2^1023 です。
小数点直下から52ビット連続の1を1023ビット左シフトした値なので、結果は小数点の上に1023-52=971ビットの0が続きます。
その値から、高々123456789.0を引いても、小数点の上971ビット目は1ですので切り上られて元に戻ってしまいます。

小さな10進数の値で考えると分かりやすいです。
50,000から100引くと49,900となります。この1,000の桁を四捨五入したら50,000に戻るという現象です。

投稿2016/07/09 17:15

編集2016/07/09 17:21
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yama_da

2016/07/11 02:53

1. 111...(52bit)....11*2^1023 を1023bit左シフトすると 1111111.....(53bit).....11110000000.....(971bit).......00000.0 になって、このでかい値から123456789.0の2進数(何桁になるかは分からないけど)の値を引いたところで結果はたいして変わらないから、971bit目の値で切り上げられて元に戻る 上の解釈で合っていますか?違っていたら訂正お願いします。 あと、小数点の上の971bit目で切り上げられるのは、doubleの仮数部が52bitで小数点以下52桁までしか表せないからですか?
Chironian

2016/07/11 02:57

> 上の解釈で合っていますか? あってますよ。 > あと、小数点の上の971bit目で切り上げられるのは、doubleの仮数部が52bitで小数点以下52桁までしか表せないからですか? 考え方はその通りです。
yama_da

2016/07/11 03:06

返信ありがとうございます。 もうひとつ質問なのですが、そうする必要があるのかどうかは抜きにして、DBL_MAXから1引いた値を得ることは不可能ということでしょうか?
Chironian

2016/07/11 10:40

yohhoyさん。 なるほど。フォローありがとうございます。
yama_da

2016/07/13 03:55 編集

色々ありがとうございました。 最初の問題は別の方法で解決出来ました。 また機会があればよろしくお願いします。 yohhoyさんもありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問