VC++6.0 でプログラムの勉強をしています。
キーボードで値を入力し、その入力した値がどのような値かチェックするプログラムを
作りたいと思っています。
値のチェックについてですが、①~④の4項目のチェックを行います。
①正の値か? ← 正常に動作しているようです。
②整数か? ← 正常に動作しているようです。
③小数点第1位までの値か? ← 例えば 5.6でも小数2位まであると判断されてしまい
ます。
④小数点第2位以下の値か? ←
下記プログラムでは、例えば 5.6 と入力しても小数第2位以下にも値があると判断され
てしまいます。
どのように修正したら良いでしょうか?
よろしくお願い致します。
#include <stdio.h>
#include <math.h>
int main( void )
{
double d; //変数d
double decimal; //変数dの少数点以下
printf( double入力 = );
scanf( %lf, &d );
if(d < 0){
printf( 正の値を入力して下さい。\n);
} else {
//小数部分 = 元の変数 - 整数部分
decimal = d - floor(d);
//入力された値が整数なら終了
if( decimal == 0){
printf( 入力された値は整数です。\n );
return 0;
}
//////////////////////////////////////////////////////////////////
//// 小数第2位以下も入力されたか、チェックする。
//////////////////////////////////////////////////////////////////
while ( decimal >= 0.1 ){
decimal -= 0.1;
}
//// ここまで。 decimalが0なら、第1位までの値。
/////////////////////////////////////////////////////////////////
//小数第1位まで入力された場合。
if(decimal == 0){
printf( 小数点第1位までの値です。\n );
}
//小数第2位以下も入力された場合。
else{
printf( 小数第2位以下も入力されました。\n );
}
}
return 0;
}
10進数の5.6を2進数で表すと循環小数になりますので、
誤差が発生します。
入力を文字列で受け取って、小数点以下の長さを調べるのがよいでしょう。
浮動小数点型であるdoubleでは誤差が出るのは当然です。
ですのであまり制度の高いような処理は出来ません。
参考
http://www.cc.kyoto-su.ac.jp/~yamada/programming/float.html#ketaoti
# 基本情報処理の最初のほうの知識なんだけど、
# いまの記述者は知らないのかなぁと。
double型に格納せず、文字列として扱うのではだめなんでしょうか?
追記:
私ならatofを自作するかな。
double my_atof(const char *str, int *digit);
digitに小数点以下の桁数を入れる。
double はそういうものだ
0.1 は10進数表記なら有限桁で表現できるけど
2進数表記では循環小数になり無限桁が必要になるわけだが
double は有限桁数しか保持できないので d-=0.1; を繰り返すと誤差が積算する。
こういう場合は逆の発想で片付けよう
小数点下に1桁しかない = 10倍すると小数点下が無い
小数点下に2桁しかない = 100倍すると小数点下が無い ...
と書いてみたが多分これでも double を使う限り期待の動作はしないと思うぞ
こーいう処理はよくあるけど
・固定小数点数型を(自作して)使う
・文字列のまま扱う
のどちらかが鉄板だな
ちなみに小数点であって決して少数点ではないので注意
誤記だらけだったので修正 orz
>ですのであまり制度の高いような処理は出来ません。
ですのであまり精度の高いような処理は出来ません。
># いまの記述者は知らないのかなぁと。
# いまの'若い'技術者は知らないのかなぁと。
私なら入力は文字列で受け取って、計算するときは
DECIMALとかCURRENCYとかでやるかなぁ。
まぁ、今回は計算することがないので文字列で扱えば十分ですけど。
たいちうさん、Blueさん、tetrapodさんありがとうございます。
>double はそういうものだ
そういうもの何ですね。
以前Excelの表計算で誤差が出たことがあったのですが、
その失敗が生かされていませんでした。
>入力を文字列で受け取って、小数点以下の長さを調べるのがよいでしょう。
みなさんがおっしゃるように、doubleでは上手くいかないようなので、
文字列で考え直してみようと思います。
>小数点下に1桁しかない = 10倍すると小数点下が無い
>小数点下に2桁しかない = 100倍すると小数点下が無い ...
もしかしたら小数点以下の値が、0.1(0.09999999999999・・・・・)
である場合も考えられそうなので、今回は文字列で書き直してみようと思います。