27

私のアプリケーションは、文字のみを受け入れるパイプに書き込むために、double値をchar*に変換する必要があります。これを行う通常の方法は、sprintf()関数を使用するか、iomanip.hヘッダーファイルのostringstreamを使用することです。

結局のところ、これらは両方とも本当に悪いパフォーマンスを持っています。そして、私のアプリケーションはこの変換を頻繁に行う必要があるため、それが主要なボトルネックになります。

他に使える機能はありますか?効率的な変換関数を作成するためにどのロジックを使用できますか?私がこれまでに思いついたのは、除算とmod演算を使用して個々の桁を取り出し、これらの桁をchar *に追加して、double値全体を取得することだけです。ただし、これは良いアプローチとは思えず、パフォーマンス自体が悪い可能性があります。

よろしくお願いします。

編集:char*がどのように使用されるかについていくつかの混乱があります。char *は、パイプに書き込むfwrite関数の引数になります。

4

9 に答える 9

19

double型がサポートできる任意の数を印刷したい場合は、そこにあるライブラリを使用して作業を行ってください。それはあなたの正気を救います:なぜ「dtoa.c」はそんなに多くのコードを含んでいるのですか?

数値のサブセットをdouble型で出力する場合。たとえば、小数点以下4桁まで、小数点前5桁以下の場合、除算とmodを使用して出力する前に、数値を丸めてint型に変換できます。このメソッドのパフォーマンスを確認できます。


編集: 本来の目的が通信用のデータを送信することである場合、doubleのバイナリ形式を送信するのが最も速く、最も正確な方法になります(変換によって精度が低下する可能性はありません)。これを行う方法は、他の回答で説明されています。

于 2012-05-25T06:48:20.213 に答える
10

std::ostreamメソッドwriteとstd::istreamreadメソッドは、データをcharポインターとして再解釈する必要がある任意のデータ型で使用できます。

double value = 5.0;
std::ostream os;
//...
os.write(reinterpret_cast<const char*>(&value), sizeof(value));
//..
std::istream is;
is.read(reinterpret_cast<char*>(&value), sizeof(value));
于 2012-05-25T06:53:21.157 に答える
7

データをバイト単位で読み取りたい場合。このテクニックを使用する

double dbl = 2222;
char* ptr = (char*)(&dbl);

これにより、dblの最下位バイトが返されます。ptr++はdblの2番目のバイトを参照します。

于 2012-05-25T06:45:01.760 に答える
4

パイプの両端を制御していますか?ダブルスをトンネリングしようとしているだけですか、それともダブルスの有効なテキスト表現が必要ですか?

トンネリングを行っているだけで、パイプが8ビットクリーンの場合は、上記の回答のいずれかを使用してください。

文字列が必要な場合は、上記の他の回答のいずれかを使用してください。

パイプの幅が7ビットしかないことが問題である場合は、書き込み時に基数64に変換し、読み取り時に再度変換します。

于 2012-05-25T13:09:00.167 に答える
2

一部のシステムは、変換機能を提供dtostredtostrfます-ベンチマークする価値があるかもしれません。sprintf()ソースコード(GNUバージョンなど)でアイデアを確認したり%e、必要に応じてフォーマットしたり、フォーマット文字列の解釈手順を回避したり、パフォーマンスを調整したりすることができます。削除できる場合があります。NaN、無限大、およびその他の値を処理する必要がないことがわかっている場合は、それらの値のための特別なケーシング。%f%g

于 2012-05-25T06:46:47.793 に答える
2

システムの遅い部分はsprintf、必ずしもdoubleの変換ではなく、フォーマット文字列の解析である可能性があります。それはあなたが最適化できるものなので、それはあなたにとって良いニュースかもしれません。

doubleさらに、処理する必要のある値の範囲、精度、および性質に関するすべての知識を文書化するように努め、それを使用して特別なアルゴリズムを開発します。

入力が非正規化数になることはないと仮定し、既知の固定精度と精度を使用すると、比較的高いパフォーマンスの結果は次のようになります。

itoa((int)((f + 0.00001) * 10000))

ただし、すでに知っているアプローチは、完全に一般的で移植可能な唯一のソリューションですsprintfostream

于 2012-05-25T07:00:23.047 に答える
2
/*

_ecvt_s Converts a double number to a string.

Syntax:

errno_t _ecvt_s( 
   char * _Buffer,
   size_t _SizeInBytes,
   double _Value,
   int _Count,
   int *_Dec,
   int *_Sign
);

[out] _Buffer
Filled with the pointer to the string of digits, the result of the conversion.

[in] _SizeInBytes
Size of the buffer in bytes.

[in] _Value
Number to be converted.

[in] _Count
Number of digits stored.

[out] _Dec
Stored decimal-point position.

[out] _Sign
Sign of the converted number.


*/


#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

...
char *buf = (char*) malloc(_CVTBUFSIZE);
int decimal;
int sign;
int err;


err = _ecvt_s(buf, _CVTBUFSIZE, 1.2, 5, &decimal, &sign);

if (err != 0) {
// implement error handling
}
else printf("Converted value: %s\n", buf);

...

お役に立てれば。

于 2012-05-25T12:01:38.433 に答える
1

これが内部で使用しているものであるため、使用ftoaする方がわずかに優れています。ここでsprintf関連する質問を参照してください 。また、ライブラリソースにftoaがどのように実装されているかを確認し、特定のシナリオでftoaを改善できるかどうかを確認してください。

それftoaはまったく標準ではないようです、私の悪いことです。これは、 sprintfよりもはるかに高速であると主張する実装を示す議論です。両方を独自のターゲット環境でプロファイリングし、floatではなくdoubleで実装する必要があります。

于 2012-05-25T06:50:43.237 に答える
0

dtostreに関しては、拡張バージョンdtostren0(https://github.com/63n0m3/Stdlib_extension)もあります。このバージョンでは、プログラマーは、返された数値を人間にわかりやすい方法で(e + nなしで)表示する小数点以下の桁数を決定できます。普通の人間が書く方法。それはまだ元のdtostreに依存します。開示:私は著者です。

于 2021-11-13T07:22:29.940 に答える