• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:long double型の戻り値を持つ関数について)

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

このQ&Aのポイント
  • StrToFloat()を用いた文字列の浮動小数点変換でケタ落ちが発生する
  • 関数の戻り値がケタ落ちしてしまう理由について解説
  • ポインタを使った関数の変更でもケタ落ちが解消されない

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

  • ベストアンサー
  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.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 の精度がありません。

hungrycat
質問者

お礼

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

その他の回答 (2)

  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.2

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
質問者

補足

回答ありがとうございます。 説明不足だったようなので、少し補足しておきます。 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 はこれまでに使ったことがなかったので、マニュアルで調べているところです) なにか心当たりの原因があるでしょうか?? お手数をかけてすみません。。

  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.1

実際に、文字列を実数に変換しているところは、どうなっているのでしょう? 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) としたほうが良いです。

関連するQ&A