0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

数値型の比較メモ

Posted at

概要

よく使われる数値型

C glib gsl OpenGL
char gchar GLchar
short gshort GLshort
long glong
int gint, gboolean GLint
unsigned char guchar GLubyte, GLboolean
unsigned short gushort GLushort
unsigned long gulong
unsigned int guint GLuint
float gfloat GLfloat
double gdouble (標準) GLdouble

複素数のための型

C99以降 gsl fftw
_Complex,二項演算子で演算可 構造体,演算用の関数あり 配列,演算用の関数なし
ただし適切に <complex.h>を読み込めばgsl, fftwともにCの複素数型と同じになる(gslは2.7以降かつC11以降, fftw は C99以降)

はじめに

gsl (Gnu Scientific Library) の design principle は以下のドキュメントにまとめられています。
https://www.gnu.org/software/gsl/design/gsl-design.html
Standards and conventions の章で glib に言及されており、曰く

  • We follow the conventions of the glib GTK support Library.

と示されています。となれば glib や gtk との相互運用性を期待したいところですが、実際は gsl そのものの設計哲学もあり、そのまま利用出来るものではないようです。
ここでは、gsl をベースに、glib をはじめ fftw や gmp といったライブラリについて、よく使われる型の比較を行います。

主な数値型の比較

gslの場合

The library is written in ANSI C and is intended to conform to the ANSI C standard (C89).
It should be portable to any system with a working ANSI C compiler.

https://www.gnu.org/software/gsl/doc/html/usage.html#ansi-c-compliance (ansi-c-compliance)

In general, the algorithms in the library are written for double precision only.
The long double type is not supported for actual computation.

https://www.gnu.org/software/gsl/doc/html/usage.html#long-double (long-double)

というわけで gsl は数をあらわす型について、独自の型があるわけではなく、C の数値型が用いられています。
また、実数の数値型としては、特段の指示がない場合 double が使われています。

さらに、行列やベクトルを扱うための型として、gsl_block ならびに gsl_vectorgsl_matrix 型もあります。
これらは上記の型を要素として作成することができます。

各ライブラリや関数の型を表すために、関数名やライブラリ名に加えて数値の型を示すことがあります。
ライブラリ名を foo とし、その中にある関数を fn( ) とするなら、これらは以下のようなネーミングとなっています。

gsl_foo_fn               double
gsl_foo_long_double_fn   long double
gsl_foo_float_fn         float
gsl_foo_long_fn          long
gsl_foo_ulong_fn         unsigned long
gsl_foo_int_fn           int
gsl_foo_uint_fn          unsigned int
gsl_foo_short_fn         short
gsl_foo_ushort_fn        unsigned short
gsl_foo_char_fn          char
gsl_foo_uchar_fn         unsigned char

glibの場合

https://github.com/GNOME/glib/blob/main/glib/gtypes.h
に別名が示されています。
https://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/glib/glib-fundamentals.html
等を確認してもよいでしょう。

typedef char   gchar;
typedef short  gshort;
typedef long   glong;
typedef int    gint;
typedef gint   gboolean;
typedef unsigned char   guchar;
typedef unsigned short  gushort;
typedef unsigned long   gulong;
typedef unsigned int    guint;
typedef float   gfloat;
typedef double  gdouble;

さらに、glib では GVariant を用いることで構造体や複雑なデータ構造を網羅した型を作成することができます。
数値関連の型は以下のようになっています。

Character	Equivalent C type
b	gboolean
y	guchar
n	gint16
q	guint16
i	gint32
u	guint32
x	gint64
t	guint64
h	gint32
d	gdouble

GVariant はglibで扱うことができる、とても強力なデータ型で、以下のように説明されています。

GVariant is a variant datatype; it can contain one or more values along with information about the type of the values.

A GVariant may contain simple types, like an integer, or a boolean value;
or complex types, like an array of two strings, or a dictionary of key value pairs.
A GVariant is also immutable: once it’s been created neither its type
nor its content can be modified further.

さらに、Cでオブジェクト指向のシステムを導入する GObject を用いる方向に話が広がっていきます。

GObject, and its lower-level type system, GType, are used by GTK and most GNOME libraries to provide:

  • object-oriented C-based APIs and
  • automatic transparent API bindings to other compiled or interpreted languages.
  • A lot of programmers are used to working with compiled-only or dynamically interpreted-only languages and do not understand the challenges associated with cross-language interoperability. This introduction tries to provide an insight into these challenges and > * briefly describes the solution chosen by GLib.

ここまで手を出すならもう C++ に移行したほうがいいんじゃないかという気がしますが、歴史的な経緯から GTK で頻繁に出てくるものなので、GTK を使う場合は手を出さざるを得ないものになるでしょう。

OpenGL の場合

ちょっと興味が出たのでついでに調べてみました。たとえば Ubuntu 20.04 で libgl-dev を導入すると /usr/include/GL/ 以下にヘッダファイルが入りますので、これを確認します。それぞれの型が何ビット持つかについては、アーキテクチャの差をヘッダファイルで吸収して、揃うようにしてあるようです。

複素数

gslの場合

gslで用いる複素数は構造体として定義されています。

typedef struct
{
double dat[2];
} gsl_complex;

ただし、gsl-2.7 以降では、

If a C compiler is available which supports the C11 standard,
and the <complex.h> header file is included prior to gsl_complex.h,
then gsl_complex will be defined to be the native C complex type:

typedef double complex gsl_complex

Some compilers, such as the gcc 4.8 series implement only a portion of
the C11 standard and so they may fail to correctly compile GSL code
when a user tries to turn on native complex functionality.
A workaround for this issue is to either remove <complex.h> from
the include list, or add -DGSL_COMPLEX_LEGACY to the compiler flags,
which will use the older struct-based definition of gsl_complex.

となっているので、C11に準拠するCコンパイラで <complex.h> ヘッダを適切にインクルードすれば、C11と同じ複素数型となり、二項演算子による四則演算が可能になります。
なお、注釈にあるように、コンパイラが微妙に古い(C99には対応するがC11に対応していない?)場合は、コンパイラオプションを設定するなどして GSL が <complex.h> を使用することを回避する必要があります。

もちろん gsl_complex 型の変数の演算が面倒なことになるので、Cコンパイラやgslのバージョンは新しくしておきたいところです。

fftwの場合

信号処理や画像処理などで頻繁に利用される fftw では、複素数は配列として定義されています。

typedef double fftw_complex[2];

ただし、

Alternatively, if you have a C compiler (such as gcc) that supports the C99 revision of the ANSI C standard, you can use C’s new native complex type (which is binary-compatible with the typedef above). In particular, if you #include <complex.h> before <fftw3.h>, then fftw_complex is defined to be the native complex type and you can manipulate it with ordinary arithmetic (e.g. x = y * (3+4*I), where x and y are fftw_complex and I is the standard symbol for the imaginary unit);

とありますので、gsl同様に<complex.h>ヘッダを適切にインクルードすれば C99 と同じ複素数型となり、二項演算子による四則演算などが可能な数値型になります。互換に必要なCのバージョンがgslより低いのは、C99の範囲で置き換えることが出来たからかな、と思います。利用者が fftw_complex 型同士で演算することは、おそらく考慮されていないことから、必要となる対応作業が少なくて済んだのかもしれません。

なおfftwの機能はgslにもありますが、gslのドキュメントによれば

For large-scale FFT work we recommend the use of the dedicated FFTW library by Frigo and Johnson.

とのことなので、取り扱うデータの規模に応じて適切にライブラリを選ぶことになろうかと思います。

glibの場合

glibに複素数型は存在しないようなので、複素数を扱いたい場合は C99以降の複素数型か gsl などライブラリを使うことになります。後者の場合は四則演算のレベルで関数などが必要になるので気を付けましょう。

おわりに

いくつかのライブラリで数値型がどのように扱われているかを比較しました。どのライブラリも基本的にCの標準的な型を踏襲しており、複素数型のようなCにとって後発の型はライブラリが独自に実装せざるを得ず、後になって標準に取り込まれたものに合わせる、というスタイルをとるようです。
<tgmath.h>をあわせて活用し、C標準の計算精度の範囲内で様々なライブラリをうまく使いこなせるとよいですね。

蛇足
Cからプログラミングを覚えた人にとって、次の選択肢は
  1. 外部ライブラリに依存出来ない状況でもプログラムを書けるようになること(組み込み系とか競プロ系とか?)
  2. よりライブラリの豊富な C++ を使えるようになること(オブジェクト指向に向かうということ? あるいはJava?)
  3. python, go, rust, C#, TypeScript などを使えるようになること(プログラミングの目的が定まったら見えてくる?)
  4. VBA, GAS, Mathematica, MATLAB などを使えるようになること(特定分野のプロプライエタリ?な開発環境に慣れる?)

といったところでしょうか。Cのまま様々なライブラリを使って頑張るのは 1. と 2. の間くらいにいるのではないかと思います。
プログラミングの教授法として近年では python から入るパターンも増えているようなので、Cを汎用的低水準言語として位置付け、そこから積み上げる、という発想は、もはや古いものなのかもしれません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?