文字列を浮動小数点に変換したいと思っています。
StrToFloat()を用いたのですが、有効数値がケタ落ちしてしまいました。
そこで、次のように関数を定義して実行したところ、やはり戻り値の値がケタ落ちしました。
long double StrToValue(AnsiString str)
{
・・・・・
return value;
}
具体的にはlong doubleの有効数値がdouble型の有効数値にまで落ちてしまっています。
次にポインタを使い、次のように変更したのですが、結果は同じでした。
void StrToValue(AnsiString str, long double *value)
{
・・・・・
*value=・・・;
・・・・・
}
どなたか、この解決方法と、できれば理由を教えてください。
なお使用した言語は、C++Builder 5
環境はWindows 98 です。

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

A 回答 (3件)

> そこで、デバッガを使って調べたところ、StrToValue(AnsiString str)のreturn直前では、


>  result=-1.55519334183474013
> となっており、str を正確に数値に変換していました。

ということであれば、可能ならば、関数の宣言から _fastcall を外すと、
回避できるかもしれません。


> long double convert_2(char* str)
> {
>   long double ret;
>   double a;
>   sscanf(str, "%lf", &a);
>   ret = a;
>   return ret;
> }
> a-kuma さんに作っていただいたこのプログラムでも、ret の値はreturn したときに後ろの数桁が消滅すると思われます。

こっちの関数は、*わざと* 精度を落としています。文字列→実数の展開を
double で(つまり、%lf を使って)いるので、ret に代入している時点で
long double の精度がありません。
    • good
    • 1
この回答へのお礼

ありがとうございました。
関数の宣言から__fastcallを外して、TGraphFormのメソッドではない独立の関数にしたところ、うまく行きました。

いろいろお手数かけてすみませんでした。。

お礼日時:2001/07/18 00:03

C++Builder を持っていないので、他のコンパイラで試してみました。



試してみたコンパイラでは、long double を printf(),scanf() で扱うとき
の書式指定子には %Lf を使います(C++Builder では、違うかもしれません)。

で、文字列を long double に変換する関数を二つ書いてみました。

#include <stdio.h>

/* きちんと long double で扱う */
long double convert_1(char* str)
{
  long double ret;
  sscanf(str, "%Lf", &ret);
  return ret;
}

/* double で扱う */
long double convert_2(char* str)
{
  long double ret;
  double a;
  sscanf(str, "%lf", &a);
  ret = a;
  return ret;
}

int main()
{
  char* str = "1111.1111111111111111111111111111111111111";
  long double a;
  a = convert_1(str);
  printf("%30.20Lf\n", a);
  a = convert_2(str);
  printf("%30.20Lf\n", a);
  return 0;
}

実行結果は、以下の通りです。

% prog
1111.11111111111111111111
1111.11111111111108584737

「桁落ちする」ってのは、こういうことですか?

この回答への補足

回答ありがとうございます。
説明不足だったようなので、少し補足しておきます。

StrToValue(AnsiString str)の実装部分は次の通りです。

long double __fastcall TGraphForm::StrToValue(AnsiString str)
{
long double count,result;
int k;
bool pm;
k=str.Pos(".");
if(k!=0) //小数点がある場合
{
result=StrToFloat(str.SubString(1,k)); //resultに整数部分を代入
}
else
{ //小数点がない場合
result=StrToFloat(str.SubString);
return result;
}
if(StrToFloat(str)>=0) pm=true; //正の場合
else pm=false;
str.Delete(1,k); //先頭から小数点までを削除

count=1.00000000000000000000000000000000000;
count/=10;
while(str!="")
{
if(str.SubString(1,1)!="E")
//小数点以下の数値を1文字ずつresultに加えていく
{
if(pm)
result+=StrToFloat(str.SubString(1,1))*count;
else
result-=StrToFloat(str.SubString(1,1))*count;
}
else
{
str.Delete(1,1); //E-10など の計算
result*=pow(10,StrToInt(str));
break;
}
str.Delete(1,1); //先頭の文字を削除
count/=10;
}

return result;
}

StrToValue(AnsiString str) を実際には次のように使っています。

void __fastcall TGraphForm::Input(AnsiString line)
{
long double RS;
・・・
RS=StrToValue(str);
・・・
}


str="-1.55519334183474013"
であるときに StrToValue(str) を実行したところ、
RS=-1.5551933418347
となりました。後ろの数桁が消滅してしまっています。
そこで、デバッガを使って調べたところ、StrToValue(AnsiString str)のreturn直前では、
 result=-1.55519334183474013
となっており、str を正確に数値に変換していました。
しかし、return 後RSを調べたところ、やはり
RS=-1.5551933418347
でした。


long double convert_2(char* str)
{
  long double ret;
  double a;
  sscanf(str, "%lf", &a);
  ret = a;
  return ret;
}
a-kuma さんに作っていただいたこのプログラムでも、ret の値はreturn したときに後ろの数桁が消滅すると思われます。
(sscanf はこれまでに使ったことがなかったので、マニュアルで調べているところです)

なにか心当たりの原因があるでしょうか??
お手数をかけてすみません。。

補足日時:2001/07/17 02:44
    • good
    • 0

実際に、文字列を実数に変換しているところは、どうなっているのでしょう?



long double StrToValue(AnsiString str)
{
  long double value;
  value = str.ToDouble();
  return value;
}

なんて、やってる?

であれば、ToDouble() 自体が double を返すメソッドですから、精度が落ちる
のは仕方ないですよね。

また、有効桁が落ちているのはどうやって確認したのでしょう?

C++Builder の printf() や iostream は long double に対応しているので
しょうか?

# C++Builder を持ってないので、想像で書いてます


因みに、本題とは外れますが、

> long double StrToValue(AnsiString str)

は、str の内容を変える関数ではないでしょうから、プロトタイプは

long double StrToValue(const AnsiString& str)

としたほうが良いです。
    • good
    • 0

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

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

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

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

QC言語のソースコードの書き方

C言語のソースコードの書き方に関する質問です。
0を5個と1を4個の、合わせて9個の数字を並べて出来上がる数列のパターン(126通り)を全て羅列させるプログラムを作りたいと考えていますが、そのためにどういった方針を立ててソースコードを書けばよいかが分かりません。
どういった構造かだけでも構いませんので、教えて頂けると幸いです。
よろしくお願いします。

Aベストアンサー

という方針で書くとこんな感じね。
#include <stdio.h>

void
print_pattern(char pattern[], int size)
{
for (int i = 0; i < size; i++) {
printf("%c", pattern[i]);
}
printf("\n");
}

void
iter(char pattern[], int end, int n, int m)
{
if (n == 0 && m == 0) {
print_pattern(pattern, end);
return;
}

if (n == 0) {
pattern[end] = 'b';
iter(pattern, end + 1, n, m - 1);
return;
}
if (m == 0) {
pattern[end] = 'a';
iter(pattern, end + 1, n - 1, m);
return;
}

pattern[end] = 'b';
iter(pattern, end + 1, n, m - 1);
pattern[end] = 'a';
iter(pattern, end + 1, n - 1, m);
}

int
main(void)
{
int m = 5, n = 4;
char pattern[m + n];
iter(pattern, 0, m, n);
return 0;
}

という方針で書くとこんな感じね。
#include <stdio.h>

void
print_pattern(char pattern[], int size)
{
for (int i = 0; i < size; i++) {
printf("%c", pattern[i]);
}
printf("\n");
}

void
iter(char pattern[], int end, int n, int m)
{
if (n == 0 && m == 0) {
print_pattern(pattern, end);
return;
}

if (n == 0) {
pattern[end] = 'b';
iter(pattern, end + 1,...続きを読む

Qtry{}catch(){}とデストラクタの関係を教えてください。

try-catchでメモリ確保を含むクラスをスローした場合、デストラクタはどの時点で働くのか、教えてください。たとえば、↓の使いかたは大丈夫でしょうか?

【1】
try{
 throw(CError(100, "エラー情報"));
}catch(CError& err){
 //ここでerrを参照しても問題ないのでしょうか?
}

【2】
try{
 CError err(100, "エラー情報");
 throw(err); // (1)
}catch(CError& err){
 //ここでerrを参照しても問題ないのでしょうか?
 //まだデストラクタはちゃんと動作するのでしょうか?
 //catchが呼び出し元のメンバであったりしても大丈夫なのでしょうか?
}

宜しくお願いします。

Aベストアンサー

【1】【2】どちらの場合も問題がありません。
コンパイラが必要に応じてerrオブジェクトのコピーを作成します。
デストラクタが呼び出されるタイミングはコンパイラに依存するところもあると思いますが、
例えばVC7.1では【2】は以下のように動作します。
(1) errオブジェクトのコンストラクタが呼び出される
(2) CErrorクラスのテンポラリオブジェクト(以下a)のコピーコンストラクタが呼び出される。
(3) errオブジェクトのデストラクタが呼び出される
(4) catch文まで到達
(5) aオブジェクトのデストラクタが呼び出される。

VC7.1では、【1】は以下のように動作します。
(1) errオブジェクトのコンストラクタが呼び出される
(2) catch文まで到達
(3) errオブジェクトのデストラクタが呼び出される。

コンパイラがオブジェクトのコピーを省略しているようです。

QC言語のソースコードについて教えてください。

以下のソースコードを学習用C言語開発環境で行ったのですが、
『ファイル「C:/Users/ユーザー名/AppData/Local/EasyIDEC/project/タイトル/main.c」の
「41行目」で記述エラーを発見しました。
「,」を付け忘れています。』

という、コンパイルエラーが表示されました。
何度も見直したのですが、よくわかりません。

#include <stdio.h>

int main(int argc, char *argv[])
{
char answer ;
answer = 'n' ;

while(answer =='n')
{
int input ;
input = 0 ;
int add ;
add = 1 ;
int sum ;
sum = 0 ;

printf("数値を入力して下さい。:") ;
scanf("%d", &input ) ;

int i ;
i = 0 ;

while(i < input)
{
sum =sum + add ;
printf("\n%d",sum) ;
i++ ;
add++ ;
}

printf("\n1から%dまでの総和は、%dです。" , input , sum) ;

while(1)
{

printf("\n終了しますか? y/n:") ;
scanf(" %c , &answer) ;

if( (answer != 'y') && (answer != 'n') )
{
printf( "y or nを入れてください。") ;
}
else
{
break ;
}
}
}
return 0 ;
}

以下のソースコードを学習用C言語開発環境で行ったのですが、
『ファイル「C:/Users/ユーザー名/AppData/Local/EasyIDEC/project/タイトル/main.c」の
「41行目」で記述エラーを発見しました。
「,」を付け忘れています。』

という、コンパイルエラーが表示されました。
何度も見直したのですが、よくわかりません。

#include <stdio.h>

int main(int argc, char *argv[])
{
char answer ;
answer = 'n' ;

while(answer =='n')
{
int input ;
input = 0 ;
int add ;
add = 1 ;
int sum ;
sum = 0 ;

printf("...続きを読む

Aベストアンサー

>>おかげで、エラー表記されずに、プログラムが実行されました。

これはコンパイルがうまく完了したってことでしょうか?できあがったプログラムが実行できたってことではないですよね?そうなら

>>’タイトル’は内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。」

なんて問題は起きないはすですからね。

できあがったファイルは、XXXX.EXEのように拡張子のEXEがついていますか?もしXXXX.OBJであれば、リンクができていませんから、実行できません。

学習用C言語開発環境の使い方を確認してみてください。

P.S.
昔は、コンパイラを使うのは大変でしたが、今は楽ですね。CではなくPascal系コンパイラーですが、カセットテープに入っていて、コンパイラの読込にテープレコーダで15分かかったりとか、まあ大変だけど面白い時代でした。

Q変数の型でlong longとunsigned long longと言うのは何ですか?

教えていただきたいのですが、変数の型にlong longやunsigned long long
なるものがあると聞いたのですが、どのようなものでしょうか?
また、どのように宣言するのでしょうか?通常のlongなどと同じ要領で宣言し
てやれば良いのでしょうか?
もし、この型がある場合に、制約はあるのでしょうか?Unixでしか使えないとか
の制約等ありましたらぜひ教えてください。
お願いいたします。

Aベストアンサー

long longはANSI-Cの新しい改訂版C99で正式に採用されました。
C99以前のANSI-C対応処理系では独自拡張(gccなど)です。
環境の指定が無いので独自拡張は無視してANS-C99について解答します。

long longまたはlong long int=64ビット符号付き整数
unsigned long longまたはunsigned long long int=64ビット符号無し整数

定数の場合はLL(=long long)またはLLU(=unsigned long long)を付加する。
LL,LLU小文字でもよい。
1LL,0LL,100000000000lluなど

long long系の整数使うライブラリ関数について
・printf/scanf系書式の追加
%lld(=long long) および%llu(=unsigned long long)
・その他ライブラリ関数
文字列整数化:strtollが用意される。

現状では日本語で読めるC99の包括的な資料は存在しません。
英語版で良ければC99のドラフトが参考URLで読むことができます。

参考URL:http://anubis.dkuug.dk/JTC1/SC22/WG14/

long longはANSI-Cの新しい改訂版C99で正式に採用されました。
C99以前のANSI-C対応処理系では独自拡張(gccなど)です。
環境の指定が無いので独自拡張は無視してANS-C99について解答します。

long longまたはlong long int=64ビット符号付き整数
unsigned long longまたはunsigned long long int=64ビット符号無し整数

定数の場合はLL(=long long)またはLLU(=unsigned long long)を付加する。
LL,LLU小文字でもよい。
1LL,0LL,100000000000lluなど

long long系の整数使うライブラリ関数について
・...続きを読む

QC言語ソースコードに関する質問です。

以下の数列について,初項から第15項までを求めるプログラムと実行結果を示せ。
0 1 1 2 3 5 8 13 21(ただし,初項=0,第1項=1とする。)

ソースコードを書くと、エラーがでた。
#include <stdio.h>
int fib(int n)
{
if(n==1 || n==2)
return 1;
else
return fib(n-1)+fib(n-2);
}
int main(void)
{
int n;
for(n=0;n<17;n++)
printf("%d,",fib(n));
}

正しソースコードを教えてください!

よろしくお願いします。

Aベストアンサー

#include <stdio.h>

void fib(int i, int j, int n)
{
if (n == 1)
{
printf("%d\n", i);
}
else
{
printf("%d\n", i);
return fib(j, i + j, n - 1);
}
}

int main(void)
{
fib(0, 1, 15);

return 0;
}

Qif(str=='a' || str=='b' || str=='c')これまとめられませんか?

題名どおりなんですが短縮してかけませんか?

Aベストアンサー

Perlなどではこういうのは正規表現で
if ( str =~ /(a|b|c)/ )

なんていうように書けます.
C言語でも正規表現を使うためのライブラリはある
(正規表現,C言語などのキーワードで検索して探してください)
ので,それを探して使うのもありかもしれません.

Qc言語のソースコードを教えて下さい

キーボードから10個の正整数値を読み込み,合計値を表示するプログラムを作りなさい。
ただし,キーボードから読み込んだ値はint型変数xにしまわれるものとし,変数はこのxと回数を数えるint型変数countと合計値をしまうint型変数sumのみを用いることとする。

このプログラムのソースコードを教えて下さい。
解説もよろしくお願いします。

Aベストアンサー

一例です。
添付のURLを参照して下さい。
因みに、平均値も算出しているが気にせずに、後はご自身で変数、コードを要調整して下さい。

参考URL:http://www.geocities.jp/kenji_y0328/crenshu/renshu/r021.gif

QSTLのto_stringにlong double

こんばんは。
STLにto_string関数を見つけました。
変数の型を見るとlong doubleもサポートしているようなので値を入れてみたところfloat値を文字列に変換したものしか得られませんでした。
どのようにすればlong doubleを文字列として取得できるのでしょうか?
環境はVisualStudio2013です。

Aベストアンサー

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

using namespace std;

int main() {
long double val = 1.0 / 3.0;

ostringstream stream;
stream << setprecision(20) << val;
string str = stream.str();

cout << str << endl;
}

/* 実行結果 (VC++12)
0.33333333333333331
*/

Qソースコードの間違い (C言語)

変数に、文字列を入れた配列の文字列の最後の要素数を入れたいのですが(つまり'\0')、うまくいきません。いつも2個多い値になってしまいます。

#include <stdio.h>

void main() {
char moji[100]={0};
int c=0;

fgets(moji,sizeof moji,stdin);

while( moji[c] != '\0' ) ++c;

printf("\n%d\n",c); //
}

例えば5文字の1ビット文字を入れると、最後の文字はmoji[4]にあるのでprintfで4と表示されるはずじゃないですか。でも6になるんです。いつも+2の値になるんですよ。どうやらfgetsを使っているからそうなるらしく、scanfを使うと結果は1多い値に、普通に配列に直接文字列を代入すると正常な結果になります。別にcに-2してもいいのですが、それはなんだか癪といいますか・・・。なぜこういうことがおきるのでしょうか?回答よろしくお願いします。

Aベストアンサー

>なぜこういうことがおきるのでしょうか
そのmoji[]の余計な部分にはどんなコードが入っているかは確認していますか?
リターンキーも「キー入力」の一つですよ。

Qlong doubleの有効桁数を教えてください。

long doubleの有効桁数を教えてください。
環境で一概に言えないと思いますが、

私の環境では、sizeof(long double)で12バイトです。
OS Windows Vista(32bit)
GCC minGW

よろしくお願いします。

Aベストアンサー

long doubleの有効桁数としてどうかは知りませんが、Intel CPUの浮動小数点レジスタは内部的には80bit(10バイト)で構成されています。コンパイラがこれを使うコードを生成しているならこの80bit浮動小数点数の精度でしょう。具体的な精度はIntelのマニュアルを確認ください。
なお、メモリ上で12バイト使うのは32bit境界への整列の関係だと思います。


人気Q&Aランキング

おすすめ情報