位置情報で子どもの居場所をお知らせ

int a;
double d;
d = 1.15 - 1.1;
a = (int)(d * 20);

この結果でaの値に1を期待しているのですが。0.9999になって結果が0になってしまいます。
他関数などを使用して良いプログラミング例はありますか?

それか、コンパイラの設定で桁数を指定して丸め込んだり出来れば解決しそうなのですが。

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

A 回答 (8件)

普通は、四捨五入に類することをやります。



a = d * 20.0 + 0.05;
(この 0.05 を必要な精度の桁数で決定する。この場合だと、小数点第2位で四捨五入)

あと、気になるところが。
> a = d * 20.0;
> これだと、コンパイルエラーです。
これは、C言語の正しい書き方です。
これでコンパイルエラーになるコンパイラは、今は存在しないと思いますが。

また、
> a = (int)(d * 20.0);
> だと、intがそれぞれにかかって、
> 結局 0 * 20 と同じ事で。
> =0

これも、int がそれぞにかかるのではなくて、
d * 20.0 の計算結果が、誤差の関係で、1.0 にならなかったから、切り捨てられて 0 になっているだけです。

一般に、double を int に代入するのに、キャストは不要です。
ですから、
a = d * 20.0 + 0.05;
という式も、右辺の式を double で計算した後、暗黙のキャストで int 型の a に普通に代入されます。

この回答への補足

ありがとうございます。
四捨五入方法、使ってみます。

C#でデバッグしてみましたが、
a = d * 20.0;は、
「型'double'を'int'に暗黙的に変換できません。明示的な変換が存在します。(castが不足していないかどうかを確認してください)」
といって警告ではなくエラーになりました。



>これも、int がそれぞにかかるのではなくて、
d * 20.0 の計算結果が、誤差の関係で、1.0 にならなかったから、切り捨てられて 0 になっているだけです。

たしかにそうなりました。

補足日時:2007/05/17 09:21
    • good
    • 1

がると申します。


小数点以下、を使うことを避けられてみては如何でしょうか?
素直に「整数のみ」で扱えるようにして、必要に応じて「表示だけ切り替える」のが、一番確実です。
浮動小数点というものは「誤差があって当たり前」のものですから。

小細工で「今回の結果を無理矢理1にすること」は可能でしょうけれども、同じ小細工を別の計算式でやると、大抵「やっぱり思ったとおりにいかない」とか言う話になり、わやくちゃになっちゃうモノなので。
    • good
    • 3

★スピードが要求されるのならばすべて int 型の整数で計算します。


・float、double 型よりも整数型の方が高速です。
 よって、100 倍した数値を int 型で表して計算すればよい。

つまり:
int a;
int d;

d = 115 - 110; ←100倍した値で計算。
a = (d * 20);
a ←100. になるが利用するときは 100 で割る。このときに float、double 型で計算する。

printf( "%lf\n", ((double)a / 100) ); ←ここで double 型にキャストして 100 で割る。

その他:
・浮動小数点は小数部を 2 進数で表すため数学的にきっちりした結果にはなりません。
 1/2、1/4、1/8、1/16、1/32…という数の合計が正確に表せる数です。
 つまり、
 0.03125
 0.06250
 0.09375
 0.12500
 0.15625
 0.18750
 0.21875
 0.25000
  :
 という数値だけが誤差がなく数を表せるのです。
・スピードが要求されるような場面では、出来るかぎり int 型の整数値を利用して下さい。
 小数として参照する直前で 100 で割るようにすればよい。または 1000 倍、10000倍にして
 計算して参照する直前で 1000、10000 で割ればよい。精度も良くなりますし、高速です。
・以上。参考に!

この回答への補足

なるほど~。
小数の仕組みわかりました。

補足日時:2007/05/17 09:36
    • good
    • 3

doubleからintに変換するときにマクロを使うとか。


#defineONROUND(a)(int)(((a)<0.0)?((a)-0.5):((a)+0.5))
な~んてね・・・
a = ONROUND(d * 20.0);
でどうでしょ?
    • good
    • 0

 double は、浮動小数点型ですので、仕様上そうなります。


 a を 1 として取り出したいのであれば、一旦、d*20 を
有効数字 小数点以下2桁の文字列にして、それを int で
読み込むのは、どうでしょうか。

int a;
double b,d;
char bb[20];

d = 1.15 - 1.1;
b = d*20.0;
sprintf(bb,"%.2lf",b);
sscanf(bb,"%d",&a);

この回答への補足

なるほど~。使えますね。
ですが、制御機器のため、スピードが要求されるので、
惜しくも、sprintfやsscanfが使えないのです。

補足日時:2007/05/16 17:09
    • good
    • 0

一介のデザイナーでプログラマではないので自信はありませんが・・・。



「プログラミング言語C」で2番目に登場する華氏の温度から摂氏の温度を求めるプログラム。

celsius = 5 * (fahr - 32) / 9;
celsius = (fahr - 32) * 5 / 9;

確か、下ではなく上の書き方をしていましたよね。

(下の書き方は)
「5 と 9 は整数だから、 5/9 は切り捨てられてゼロとなり、もちろんすべての摂氏温度がゼロになってしまう。」
(「プログラミング言語C」13頁)

この例に倣うならば・・・

Private Sub Command1_Click()
  Dim a As Integer
  Dim d As Double
  
  d = (115 - 110) / 100
  a = Int(d * 20)
  MsgBox a
End Sub

VB6.0 でも C でも通貨型を使わなければ同じことなのでVB6.0でテストしてみました。

なお、プロのプログラマの方の回答もお待ち下さい。

この回答への補足

これも使えますね。でも、こういう式を使った部分が、大量にありまして、ちょっと手作業が厳しい状態です。

少なければ私もこれでやろうかなと思ってました。

補足日時:2007/05/16 17:11
    • good
    • 0

たいていの処理系で double の値は「2進数に基づく浮動小数」で表現されるので, 2^-n という形でないと正確に表すことができません. そのようなものを有限のビット数で表現しなければならないので, 切り捨てられたり切り上げられたりします. これは double など浮動小数を使うときには常についてまわる問題なので, プログラムを書くときにきちんと注意する必要があります.


で, 対策ですが....
・そもそも double なんて使わない: 可能であればこれが最も簡単
・DBL_EPSILON を考慮してプログラムを書く: 面倒
・うまくいく関数たちを使う: 存在するかどうかは知りません
・C を使わない: C# なら OK だったと思う
かなぁ? この辺を処理する設定は, 普通はないと思います.

この回答への補足

いちお、doubleをやめて、floatにしたら、うまくいきました。
0.04999のいい具合のとこで四捨五入されたからだとおもいます。

Cでも、C#でも、Excelでも、やはり0.0499・・・82になりました。

日立のコンパイラのマニュアル見たら、小数点を切り捨てるか四捨五入かというのと、有効数字の桁数を設定するなんて書いてあったのですが、設定場所が見当たらず、日立に問い合わせ中です。

補足日時:2007/05/16 17:06
    • good
    • 0

d * 20.0



にするとどうなる?

この回答への補足

a = d * 20.0;
これだと、コンパイルエラーです。

a = (int)(d * 20.0);
だと、intがそれぞれにかかって、
結局
0 * 20
と同じ事で。
=0
になりました。

補足日時:2007/05/16 17:00
    • good
    • 0

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

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

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

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

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

Q計算の丸め誤差の解消について

プログラム上で計算するときに丸め誤差が発生し、困っています。

丸め誤差が発生している計算は
-0.004+0.006+0.002
なのですが、
-0.004+0.006+0.002=0
となるところが、 =8.47E-09
となってしまっています。
オーダーの異なる計算ではないにもかかわらず、どうして誤差が発生するのかが理解できず困っています。
上の数値(左辺の方)の算出は、10^(-1)のオーダーの数値から計算されています。

多分、浮動小数点を使っているからだろうと考えているのですが、どのように解消したらよろしいでしょうか?

固定小数点を用いると、浮動小数点より誤差が少ないとありましたが、Cで固定小数点を用いる方法もわからないです。

よろしくお願いします。

Aベストアンサー

コンピュータは2進数なので仕方がないです。
10進数では有限小数であっても、2進数に変換すると循環小数等になってしまい、正確に計算することはできません。
試しに0.1を2進数に変換してみると一目瞭然。

これはC言語やそのほか多くのプログラミング言語の制限事項です。
COBOLとかではきちんと計算できます。(だから昔から小数をきちんと計算する必要のある銀行系のシステムにCOBOLが多いのです。)

数値を文字列として読み込んで、計算ロジックは自作するのが一番簡単です。

QC++ 構造体の一括初期化 {0}

構造体変数に {0} を代入すると、CString は空文字、 intは0に一括で初期化されるようです。
なんでこんなことが出来るのでしょう?
{0}は何?
仕組みを教えて下さい!!

Aベストアンサー

> 一括初期化関数でも作るしかなさそうですね
static変数を初期化用に用意しておくのはいかが?
http://oshiete.goo.ne.jp/qa/2658268.htmlより
>静的記憶域期間をもつオブジェクトを明示的に初期化しない場合、
>次の規定に従う。
>a) そのオブジェクトの型がポインタ型の場合、空ポインタに初期化する。
>b) そのオブジェクトの型が算術型の場合、(正または符号なしの)0に初期化する。
>c) そのオブジェクトが集成体の場合、各メンバにa)~d)の規定を(再帰的に)
>適用し初期化する。
>d) そのオブジェクトが共用体の場合、最初の名前つきメンバにa)~d)の規定を
>(再帰的に)適用し初期化する。

なので、zero初期化されていることが、規格で保証されます。

typedef struct hoge_struct
{
 int a;
 int b;
} hoge_struct;

static hoge_struct initializer; //初期化用変数。値は変えない。

int main(void)
{
 hoge_struct hoge;
 hoge = initializer;
 return 0;
}
真っ白に何度も初期化したいなら、こんな感じでどうでしょう?
関数を用意して初期化すると、構造体のメンバが増えると関数も修正しないといけない
ですが、これだと関数を変更しなくてすむし。

> 一括初期化関数でも作るしかなさそうですね
static変数を初期化用に用意しておくのはいかが?
http://oshiete.goo.ne.jp/qa/2658268.htmlより
>静的記憶域期間をもつオブジェクトを明示的に初期化しない場合、
>次の規定に従う。
>a) そのオブジェクトの型がポインタ型の場合、空ポインタに初期化する。
>b) そのオブジェクトの型が算術型の場合、(正または符号なしの)0に初期化する。
>c) そのオブジェクトが集成体の場合、各メンバにa)~d)の規定を(再帰的に)
>適用し初期化する。
>d) そのオブジェクトが共用...続きを読む

QCStringからchar*への型変換について教えてください。

以前の質問に

int型 → CString型/char型

がありましたが、

CString型をchar*型に変換する方法を
教えていただければありがたいです。

MSDNで「LPCTSTRキャスト」が説明されていましたが、
例が載ってないのでよくわかりませんでした。

よろしくお願いします。

Aベストアンサー

目的にもよりますが一時的にchar配列として使いたいならCString::GetBuffer()が利用できます。
char配列としての利用が終わったらCString::ReleaseBuffer()する必要がありますが。

直接CString内の文字列を扱う必要があるならCString::operator LPCTSTRで文字列ポインタが得られます。
ただし、CStringオブジェクトをいじると無効ポインタなる可能性があるので気をつけてください。

MSDNのMicrosoft Foundation Classリファレンス→CString→クラスメンバで確認してください。

Qdoubleの変数にintとintの割り算の結果を代入するとき

以下のようにするとdには0.5ではなく0が代入されます。

int x = 1, y = 2;
double d = x / y;

これを回避するために以下のようにするのが一般的だと習いました。

//1.
double d = (double)(x) / y; // これでdには0.5が代入される

これを以下のようにしてしまうのに問題はあるでしょうか?

//2.
double d = (double)(x) / (double)(y);
//3.
double d = x / (double)(y);

また、1.と2.と3.ではどれがより良いのでしょうか?
単純に好みの問題なのでしょうか?

以上、よろしくお願いいたします。

Aベストアンサー

恐れ入ります。

単純に好みの問題かと思います。
CやC++の規格に準拠したコンパイラであれば、結果的に同じ式として扱ってくれます。
***
ただし、1,2,3ではない別種の方法を良く用いるので参考までに挙げておきます。

int x = 1;
int y = 2;
double dpoX = 0;
double dpoY = 0;
double d = 0;

dpoX = (double)x;
dpoY = (double)y;
d = dpoX / dpoY; /* 計算するときには、精度を揃えておく */

整数を使う場面では整数を使い、倍精度の計算をするときには倍精度で計算するのが良いかと。混ぜると混乱の元です。
(個人的には、ハナからdoubleで取り扱うべきかと思います)

速度的には前述の1,2,3と同様に、計測できるほどの速度低下にはなりません。
(可読性を犠牲にするのは、「除算は遅いから使いたくない」という様な時だけにする方が良いと思います)

ご参考になれば幸いです。

Qfloat型とdouble型の変数の違いを教えてほしいです

float型とdouble型の変数の違いを教えてほしいです
2Dゲームを作っててdoubleの変数を使ってたんですが使ってはだめだと先輩に言われたんです。
理由を聞いたら、先生が「doubleは使わないほうがいい」と言われたらしくてちゃんとした理由がわかりませんでした。
それを知って何をするということではないんですが、気になって調べても出てこなかったので質問させてください。
まだゲーム作りを始めたばっかりでぜんぜん詳しくないですが教えてくれたら助かります。

Aベストアンサー

doubleとfloatでは、精度が違い、そのためメモリに占める大きさも違います。
また、一般的には、桁が多いとその分計算時間がかかります。
ですから、精度が必要ない場面では、floatを使う、というのも一つの考えかたです。

ですが、実際には「一概に言えない、処理系依存」です。

以前は全てCPUで計算していたので、精度=計算量でした。
しかし、最近では浮動小数点演算専用の回路が付いているケースが多く、計算時間は同じだったり、doubleに変換が必要でその分floatの方が遅かったり、floatでの演算はより高速にできたり、と様々です。
32bitCPUでは、32bitのfloatの方が扱いやすいでしょうが、64bitCPUでは64bitのdoubleの方が扱いやすいかもしれません。
Cのmath.hで使える標準関数はdouble型のものがほとんどです。三角関数は2Dのゲームでも使う機会が多いのではないでしょうか。sinもcosもdouble型です。内部演算は当然doubleですので、変数にfloatを使ったからと早くはならず、むしろfloat型の変数に入れるときに暗黙の型変換が発生する分遅くなる可能性もあります。

そういった背景を考え検討した結果、floatを使う方がよい、と判断したのならいいのですが、「先生に言われた」では理由になりません。
聞けるのなら、その先生に理由を聞いてください。真意がわからないうちは、鵜呑みしないことです。

doubleとfloatでは、精度が違い、そのためメモリに占める大きさも違います。
また、一般的には、桁が多いとその分計算時間がかかります。
ですから、精度が必要ない場面では、floatを使う、というのも一つの考えかたです。

ですが、実際には「一概に言えない、処理系依存」です。

以前は全てCPUで計算していたので、精度=計算量でした。
しかし、最近では浮動小数点演算専用の回路が付いているケースが多く、計算時間は同じだったり、doubleに変換が必要でその分floatの方が遅かったり、floatでの演算はより高速...続きを読む

Qlong doubleの表示方法

long doubleの型を使いたいのですが、出力するとき、

printf("%e\n", A);

とすると、8桁しか出力されません。
これを16桁まで出力させる方法はないでしょうか。

Aベストアンサー

long doubleのときは、eの代わりにLeを使います。

long doubleがサポートされていたとしても、精度はまちまちです。doubleと全く同じ場合もあるでしょうし、80ビットや128ビットであることもあります。
printf("%d, %d\n", sizeof(double), sizeof(long double));
のように確認してみれば、使う意味があるかどうかはわかります。

doubleの精度は15桁なので、微妙なところですね。

Qdouble型からfloat型への型変換について

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

double -999.999000
float -999.999023

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

Aベストアンサー

> これは、単純に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-1/NUMCOMPGD/ncgTOC.html

Qfopne で失敗する原因

fopenで失敗する原因とはなんですか?

Aベストアンサー

#1の方の回答に加えて...

・ファイル名の文字列がでたらめ(存在するかどうか以前の問題)
・指定したファイル名が実はディレクトリだった。
・ファイル名に空ポインタまたは不正なポインタを渡した。
・オープンモードに空ポインタまたは不正なポインタを渡した。
・オープンモードの形式が不正
・メモリ不足でバッファ(実装によってはファイル記述子も)の割り付けに失敗した。
・同名の関数またはマクロをユーザーが定義した。
・関数原型なしで呼び出した。
・他のスレッド等で、同じファイルに対する操作中(再入可能とは限らないので)

QDWORDの実際の型は何でしょうか

VC++.NETの環境です。
DOWRD dw1 = 1;
int i = 2; と定義し
ここで
if ( i > dw1 ){
何かの処理;
}
とコーディングすると
warning C4018: '>' : signed と unsigned の数値を比較しようとしました。
のワーニングがでます。
これは、DWORDがint型でなくunsigned int型のようにも見えます。
ある本によれば(VC++.V.NET逆引き大全500の極意)
DWORD はint型であると記述されています。
もし、int型ならこのワーニングはでないはずなのですが、
なぜでるのでしょうか。又、DWORDの実際の型は何なのでしょうか。ご存じのかたおりましたら、教えていただけませんでしょうか。

Aベストアンサー

型定義が知りたいのならば、宣言ファイルを見れば疑問を挟む余地もありません。
DWORD型はwindef.hで
"typedef unsigned long DWORD;"
と宣言されています。

Visual Studioを使っているのならば、知りたい型の上にマウスポインタを置いて右クリック、ポップアップメニューの「定義へ移動」または「宣言へ移動」で簡単に知ることが出来ます。

Qstr系関数を使わずに二つの文字を結合する方法

自分で色々考えていたのですが中々分からなくて・・・

#include<stdio.h>
#include<string.h>

int moji(char* b1,char *b2)
{
char b[11];
int x;
strcpy(b, b1);
strcat(b, b2);
x = strlen(b);
return x;
}

main()
{
char a[4] = "alt";
char b[8] = "recorde";
int c;
c = moji(a, b);
printf("文字数は%d\n", c);
}

のプログラムでmoji関数の部分にあるstr~を全部接続節(for)等で作成してポイントで持ってきた文字を連結するにはどうすればいいでしょうか?

strに慣れて自分で作れなくならないためにもお力をかしいただけると嬉しいです。

Aベストアンサー

#1の回答と似たようなものですが、
--------------------------------
int moji(char *b1, char *b2)
{
  char b[256];
  int cnt=0;
  for(; *b1 != '\0'; b1++){
    b[cnt] = *b1;
    cnt++;
  }
  for(; *b2 != '\0'; b2++){
    b[cnt] = *b2;
    cnt++;
  }
  b[cnt] = '\0';
  printf("%s\n", b);  /*チェック用*/
  return cnt;
}
--------------------------------
文字数だけ欲しいなら、連結しなくてもそれぞれ文字数数えて足せばいいけど、
それは質問の趣旨に反するんでしょうね^^;


> #1
> };
whileブロックの終わりと、関数ブロックの終わりにセミコロンが有りますが、これは不必要ですよ。
空文になるので、この場合有っても実害はないかな。

> while(TRUE)
どこかでdefineしていない限り、TRUEという定数はないと思います。(C++ならtrueは有る。)
無限ループはwhile(1)で。
(b1[x]をループ継続条件にしても良さそう。)

> return y-1;
引かなくても良さそうな気が…。

#1の回答と似たようなものですが、
--------------------------------
int moji(char *b1, char *b2)
{
  char b[256];
  int cnt=0;
  for(; *b1 != '\0'; b1++){
    b[cnt] = *b1;
    cnt++;
  }
  for(; *b2 != '\0'; b2++){
    b[cnt] = *b2;
    cnt++;
  }
  b[cnt] = '\0';
  printf("%s\n", b);  /*チェック用*/
  return cnt;
}
--------------------------------
文字数だけ欲しいなら、連結しなくてもそれぞれ文字数数えて足せばいいけど...続きを読む


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

人気Q&Aランキング