6

C99 で定義されている複素数を使用したいのですが、それをサポートしていないコンパイラをサポートする必要があります (MS コンパイラが思い浮かびます)。

多くの関数は必要ありません。必要な関数をサポートなしでコンパイラに実装することはそれほど難しくありません。しかし、「型」自体を実装するのに苦労しています。理想的には、次のようなことをしたいと思います:

#ifndef HAVE_CREAL
double creal(complex z)
{
/* .... */
}
#endif

#ifndef HAVE_CREALF
float creal(float complex z)
{
/* ... */
}
#endif

しかし、コンパイラが「float complex」を認識できない場合、これを行う方法がわかりません。実際には不可能だと思いますが、Dinkumwareの C ライブラリは別の方法を示しているようです。解決策は何ですか?型の操作に関数/マクロを使用してもかまいませんが、複素数に値を代入し、C99 と互換性のある方法で実数/虚数部分を取得する方法が必要です。

解決

私は最終的に次のようなことをしました:

#ifdef USE_C99_COMPLEX
#include <complex.h>
typedef complex my_complex;
#else
typedef struct {
  double x, y;
} my_complex;
#endif

/*
 * Those unions are used to convert a pointer of my_complex to native C99
 * complex or our own complex type indenpendently on whether C99 complex
 * support is available
 */
#ifdef USE_C99_COMPLEX
typedef union {
    my_complex my_z;
    complex c99_z;
} __complex_to_c99_cast;
#else
typedef union {
    my_complex my_z;
    my_complex c99_z;
} __complex_to_c99_cast;
#endif

型定義については、次のように複雑な関数のセットを定義します。

#ifndef HAVE_CREAL
double my_creal(my_complex z)
{
    union {
            my_complex z;
            double a[2];
    } z1;
    z1.z = z;
    return z1.a[0];
}
#endif

#ifdef HAVE_CREAL
my_complex my_creal(ny_complex z)
{
    __complex_to_c99_cast z1;
    __complex_to_c99_cast ret;

    z1.my_z = z;
    ret.c99_z = creal(z1.c99_z);
    return ret.npy_z;
}
#endif

これは少し複雑ですが、これにより、利用可能な場合は C lib 関数を簡単に再利用でき、コード ジェネレーターを使用して部分的に自動化できます。

4

2 に答える 2

6

何をしても、C99 以外のコンパイラで "float complex" を適切に解析することはできません。そのため、それを記述する代わりに、いくつかの typedef を作成します。複合型を 1 つだけサポートする必要がある場合は、はるかに簡単ですfloat complex

まず、型を定義します。

#if __STDC_VERSION__ >= 199901L
//using a C99 compiler
#include &lt;complex.h>
typedef float _Complex float_complex;
#else
typedef struct 
{
    float re, im;
} float_complex;
#endif

次に、複素数を作成し、creal と cimag をエミュレートできる必要があります。

#if __STDC_VERSION__ >= 199901L
//creal, cimag already defined in complex.h

inline complex_float make_complex_float(float real, float imag)
{
   return real + imag * I;
}
#else
#define creal(z) ((z).re)
#define cimag(z) ((z).im)

extern const complex_float complex_i; //put in a translation unit somewhere
#define I complex_i
inline complex_float make_complex_float(float real, float imag)
{
    complex_float z = {real, imag};
    return z;
}
#endif

次に、加算、減算、乗算、除算、および比較をラップする関数を作成します。

#if __STDC_VERSION__ >= 199901L
#define add_complex(a, b) ((a)+(b))
//similarly for other operations
#else //not C99
inline float_complex add_complex(float_complex a, float_complex b)
{
  float_complex z = {a.re + b.re, a.im + b.im};
  return z;
}
//similarly for subtract, multiply, divide, and comparison operations.

add_complex(c, 5)上記のコードでは、C89 モードでは動作しないことに注意してください。これは、コンパイラが 5 を複素数にする方法を認識していないためです。これは、コンパイラのサポートなしで C で修正するのが難しい問題ですtgmath.h。コンパイラ固有の新しい用途のようなトリックに頼る必要があります。

a+b残念ながら、これらすべての影響は、複素数を加算するような優れた C99 構文を作成する必要があることですadd_complex(a, b)

別のオプション (別のポスターが指摘したように) は、std::complexC99 以外のコンパイラで C++ を使用することです。#ifdefこれは、typedef とsでラップできれば問題ないかもしれません。ただし、C++ または C99 が必要です。

于 2009-06-30T13:57:49.760 に答える
-1

msdn Web サイトで見つけたライブラリがあります。ここにリンクがあります。 http://msdn.microsoft.com/en-us/library/0352zzhd.aspx

それが役立つことを願っています。

于 2009-06-30T13:51:23.020 に答える