double型で-999.999という数字をfloat型へキャストして
少数以下6桁をprintf文で表示すると、それぞれ以下の様になりました。

double -999.999000
float -999.999023

これは、単純にfloatの精度の問題なのでしょうか?
また、計算機がどういうルールに基づいて計算をおこなっているということなのでしょうか?
教えてください。

このQ&Aに関連する最新のQ&A

A 回答 (1件)

> これは、単純にfloatの精度の問題なのでしょうか?



その通りです。

IEEE 754 のフォーマットにしたがった 32ビット浮動小数点表記では仮数部が
23ビットですから、高々7桁程度の精度しかありません。


> また、計算機がどういうルールに基づいて計算をおこなっているということなのでしょうか?

double → float の場合には、仮数部が 52 → 23 ビット、指数部が 12 → 8 ビットと少なくなります。
元の数値が float で表現できる範囲で収まるのであれば、仮数部のビットを切りつめて、指数部を変換する
だけです。

元の数値が float に収まりきらない場合には、overflow や underflow が発生します。

真剣に知りたいのであれば、参考URL をどうぞ。

参考URL:http://docs.sun.com/htmlcoll/coll.648.2/iso-8859 …
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qdouble型とint型で三分の一乗の計算をしたい

C#を使っています。
(double型 / double型) ^ (1 / 3)
このような計算をしたいのですが、
「エラー:演算子 '^' を 'double' と 'int' 型のオペランドに適用することはできません。」と、表示されてしまいます。
三分の一乗という計算をすることは不可能なのでしょうか。
よろしくお願いします。

Aベストアンサー

C#では ^演算子=XOR演算 です
(簡単な説明:2進数で左右の各位を比べて両方1なら0にする演算子)
11111000(10進数で248)^00111111(63)=11000111(199)

C#で冪乗をする場合は、Tacosanさんの回答にもあるように
Math.Pow関数を使います。
例:
double i = Math.Pow(10.0 , (1.0/3.0));//10^(1/3)
i=2.15443469003188

QC言語:double型での戻り値は小数点以下何桁ですか?

Cでプログラミングの勉強をしています。

double型で宣言した変数をprintfで出力するとき、代入した数値は小数点以下1桁なのに、なぜか出力結果では6桁になると問題集に書かれていました。解説はありません。

プログラムは下のものですが、なぜかお分かりになる方、教えていただけませんか?

#include<stdio.h>
struct test{
int x;
double y;
}
void print(struct test a);
void set_value(struct test a);

void main(void){
struct test a ={1, 2.0};
set_value(a);
print(a);
}
void print(struct test a){
printf("a.x = &d, a.y= %f\n", a.x, a.y);
}
void set_value(struct test a){
a.x =10;
a.y =20.0;
}

Cでプログラミングの勉強をしています。

double型で宣言した変数をprintfで出力するとき、代入した数値は小数点以下1桁なのに、なぜか出力結果では6桁になると問題集に書かれていました。解説はありません。

プログラムは下のものですが、なぜかお分かりになる方、教えていただけませんか?

#include<stdio.h>
struct test{
int x;
double y;
}
void print(struct test a);
void set_value(struct test a);

void main(void){
struct test a ={1, 2.0};
set_value(a);
pr...続きを読む

Aベストアンサー

単に桁数を指定していないからです。
何も指定しない場合、 printf は小数点以下を
6桁表示するようになっています。
そもそも、double は浮動小数点数なので
保持する桁数は予め決まっています。

後ついでに細かいミスをなどを、、、

[1] 最後のセミコロンを忘れています。
struct test {省略};

[2] &d ではなく %d です。
printf("a.x = %d, a.y= %f\n", a.x, a.y);

[3] \n ではなく \n です。
printf("a.x = %d, a.y= %f\n", a.x, a.y);

[4] set_value はポインタ渡しで。
int main() {
set_value(&a);
}
void set_value(struct test *a) {
a->x = 10;
a->y = 20.0;
}

Qprintfの精度

1/3をprintf("%g"で表示すると
0.333333
となります。
”精度”の使い方が違うかもしれませんが、
電気計算では三ケタの精度で十分なので
0.333
と表示させられないでしょうか。

Aベストアンサー

書式を
%.3g
とすればよいかと

P.S 切り捨てなので気をつけて

Qdoubleとfloatについて

#include <stdio.h>

int main()
{
float height,weight;

printf("身長と体重を入力してください。\n");
scanf("%f",&height);
scanf("%f",&weight);

printf("身長は%fセンチ:体重は%fキロです。\n",height,weight);

return 0;
}

上記のようなプログラムを作って、身長には175.1体重には56.1という入力を行なって実行したところ、
身長は175.100006センチ:体重は56.099998キロです。
という結果が返ってきました。
heightとweightをdouble型で宣言したところ(もちろんscanf文の変換仕様は%lfにしています。)、結果は
身長は175.100000センチ:体重は56.100000キロです。
と私が、期待していたものが返ってきました。なぜfloat型だと期待通りの結果が返ってこないのでしょうか?ご教授お願い致します。

#include <stdio.h>

int main()
{
float height,weight;

printf("身長と体重を入力してください。\n");
scanf("%f",&height);
scanf("%f",&weight);

printf("身長は%fセンチ:体重は%fキロです。\n",height,weight);

return 0;
}

上記のようなプログラムを作って、身長には175.1体重には56.1という入力を行なって実行したところ、
身長は175.100006センチ:体重は56.099998キロです。
という結果が返ってきました。
heightとweightをdouble型で宣言したところ(もちろんscanf文...続きを読む

Aベストアンサー

ご質問は,いわゆる2進数計算のまるめ誤差のことでしょうか.

問題は,2つあると思います.
 ・循環小数を有限ケタで切ること

 ・何桁まで表示するか?

という問題です.


・循環小数を有限ケタで切ること
コンピュータの内部は,一部を除き,
「2進数」で処理されています.

少数点以下の表し方の中には,10進数だときっちり表せるものが,2進数では,循環小数のようになって有限のケタでは正確に表せない場合が出てきます.

つまり,10進数だと
 0.1 (10^-1)
0.01 (10^-2)
0.001 (10^-3)
として,区切りですが,
2進数だと,
 0.5 (2^-1)
0.25 (2^-2)
0.125 (2^-3)
0.0625 (2^-4)
0.03125 (2^-5)
0.015625 (2^-6)
0.0078125 (2^-7)
0.00390625 (2^-8)
となり,たとえば,0.1は
 0.1(10進数) = 0*0.5 + 0*0.25 + 0*0.125 + 1*0.0625 + 1*0.03125 + 0*0.015625 + 0*0.0078125 + 1*.00390625 + ...

= 0.00011001... (2進数)
となり,2進数の世界では循環小数となります.
これを有限のケタで切ると誤差ができます.

つまり,2進数の有限のケタであらわした
0.1(10進数)を10こ足しても,
 1になりません.

・何桁まで表示するか?
そうはいっても,単精度でも,通常の使用には十分
耐える精度は持っています.
 表示桁数を少なくして,四捨五入してしまえば
みためには正解にみえるものも表示できます.
 多くの計算結果は,そのようにして表示されています.

 たとえば,さきほどの
0.00011001... (2進数)
    = 0*0.5 + 0*0.25 + 0*0.125 + 1*0.0625 + 1*0.03125 + 0*0.015625 + 0*0.0078125 + 1*.00390625
= 0.09765625 (10進数)
です.少数第3位で四捨五入すれば,
   0.1 (10進数)
です.

ご質問では,倍精度ではただしいという結果が出ていますが,0.1は2進数では循環小数ですから,倍精度といえども内部表現は不正確です.
ここでの差は単なる表示桁数の差でしょう.
単精度は,10進数で7ケタ
倍精度は,10進数で14ケタ
の精度を持っています.ご質問では,9ケタ程度表示していますので,その差がでていると思います.

ご質問者は,「電卓だとちゃんと表示するじゃないか」と思われると思います.
実は,電卓などの会計にしようされるものには,上記のような不正確さは許されません.
よって,「10進補正」といいまして,
10進数で正確に表せるように内部計算を10進数で行っているのです.
このような補正をすれば,計算速度はかなり落ちますが,10進数であらわしたものは正確に計算できます.
事務用のマシンでこの機能をもったものが多いようです.
おおくのコンピュータは,処理速度が命ですから,
2進数で計算していますだから,このような誤差は認識した上で使用すべきでしょう.



この誤差を避ける方法として,「固定小数点方式」
といいまして,
 0.1を1000000 * 0.0000001
としてあらわし,計算はすべて,整数でおこない表示だけを小数点をつけてあらわす方法です.この方法だと,整数で計算するので,上記の誤差はでません.
ただし,この方法では,極端に大きな数字
たとえば,6.02*10^24 を表すことが出来ません.
極端に小さな数字 8.854*10^-24などもあらわせません.

また,ちなみに,最近のCPUは,浮動小数計算専用のハードを実装していて,単精度も倍精度も計算時間は変わりません.ただし,メモリは倍必要になります.メモリさえゆるせば,私はすべて倍精度としています.
また,C言語では,言語の簡単化のためか,変数にfloatは存在していますが,計算時の内部処理はすべていったん倍精度に変換されてから行われます.
(単精度を倍精度に変換しても,精度はあがりませんが.)

ご質問は,いわゆる2進数計算のまるめ誤差のことでしょうか.

問題は,2つあると思います.
 ・循環小数を有限ケタで切ること

 ・何桁まで表示するか?

という問題です.


・循環小数を有限ケタで切ること
コンピュータの内部は,一部を除き,
「2進数」で処理されています.

少数点以下の表し方の中には,10進数だときっちり表せるものが,2進数では,循環小数のようになって有限のケタでは正確に表せない場合が出てきます.

つまり,10進数だと
 0.1 (10^-1)
0.01 (10^-2)
...続きを読む

Qchar型をfloat型に変換

GPSからシリアルポートに流れてくるコンマ区切りのフォーマットをいったんcharにいれて、トークンでぶちぶち切って、違う変数に格納したいです。

流れてくるデータは、
$GPGGA,042449.00,3449.30669291,N,13531.38645000,E,1,4,4.4,81.885,M,34.255,M,,*6D

のような数値です。緯度経度や日付等のデータです。

緯度や経度の数値をfloatやdoubleに変換して変数に格納したいのですが、どうしたらよいでしょうか?

そのまましたらエラーが出てしまいます。

以下は数値をブチブチ切って表示させるプログラムです。




#include <windows.h>
#include <stdio.h>


int main(void)
{
char szSend[] = "$GPGGA,000000.00,0000.00000000,N,00000.00000000,E,0,0,0.0,00.000,M,00.000,M,,*00";
char szBuf[sizeof(szSend)]="$GPGGA,042449.00,3449.30669291,N,13531.38645000,E,1,4,4.4,81.885,M,34.255,M,,*6D";



char *ptr;
ptr=strtok(szBuf,",");
printf("%s\n",ptr);//$GPGGA
ptr=strtok(NULL,",");
printf("%s\n",ptr);//時間
ptr=strtok(NULL,",");
printf("%s\n",ptr);//緯度
ptr=strtok(NULL,",");
printf("%s\n",ptr);//N北
ptr=strtok(NULL,",");
printf("%s\n",ptr);//経度
ptr=strtok(NULL,",");
printf("%s\n",ptr);//E東
ptr=strtok(NULL,",");




return 0;

}


コンパイラはmicrosoftvisualC++6.0です。

floatとかboubleにしたいのは緯度や経度の数値を計算して扱いやすいデータにするためです。

よろしくお願いします。

GPSからシリアルポートに流れてくるコンマ区切りのフォーマットをいったんcharにいれて、トークンでぶちぶち切って、違う変数に格納したいです。

流れてくるデータは、
$GPGGA,042449.00,3449.30669291,N,13531.38645000,E,1,4,4.4,81.885,M,34.255,M,,*6D

のような数値です。緯度経度や日付等のデータです。

緯度や経度の数値をfloatやdoubleに変換して変数に格納したいのですが、どうしたらよいでしょうか?

そのまましたらエラーが出てしまいます。

以下は数値をブチブチ切って表示させるプロ...続きを読む

Aベストアンサー

間違った文字列が流れて来ない事が前提なら、atofが簡単かな。

double f = atof("123.456");
printf("%f\n", f);


このQ&Aを見た人がよく見るQ&A

このカテゴリの人気Q&Aランキング

おすすめ情報