OKWAVEのAI「あい」が美容・健康の悩みに最適な回答をご提案!
-PR-
解決
済み

long double型の戻り値を持つ関数について

  • すぐに回答を!
  • 質問No.104866
  • 閲覧数769
  • ありがとう数1
  • 気になる数0
  • 回答数3
  • コメント数0

お礼率 40% (2/5)

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

質問者が選んだベストアンサー

  • 回答No.3
レベル14

ベストアンサー率 50% (1122/2211)

> そこで、デバッガを使って調べたところ、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 の精度がありません。
お礼コメント
hungrycat

お礼率 40% (2/5)

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

いろいろお手数かけてすみませんでした。。
投稿日時 - 2001-07-18 00:03:25
-PR-
-PR-

その他の回答 (全2件)

  • 回答No.1
レベル14

ベストアンサー率 50% (1122/2211)

実際に、文字列を実数に変換しているところは、どうなっているのでしょう? long double StrToValue(AnsiString str) {   long double value;   value = str.ToDouble();   return value; } なんて、やってる? であれば、ToDouble() 自体が double を返すメソッドですから ...続きを読む
実際に、文字列を実数に変換しているところは、どうなっているのでしょう?

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)

としたほうが良いです。


  • 回答No.2
レベル14

ベストアンサー率 50% (1122/2211)

C++Builder を持っていないので、他のコンパイラで試してみました。 試してみたコンパイラでは、long double を printf(),scanf() で扱うとき の書式指定子には %Lf を使います(C++Builder では、違うかもしれません)。 で、文字列を long double に変換する関数を二つ書いてみました。 #include <stdio.h> ...続きを読む
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

「桁落ちする」ってのは、こういうことですか?
補足コメント
hungrycat

お礼率 40% (2/5)

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

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:19
このQ&Aで解決しましたか?
関連するQ&A
-PR-
-PR-
こんな書き方もあるよ!この情報は知ってる?あなたの知識を教えて!
このQ&Aにはまだコメントがありません。
あなたの思ったこと、知っていることをここにコメントしてみましょう。

その他の関連するQ&A、テーマをキーワードで探す

キーワードでQ&A、テーマを検索する
-PR-
-PR-
-PR-

特集


いま みんなが気になるQ&A

関連するQ&A

-PR-

ピックアップ

-PR-
ページ先頭へ