💎

【Crystalと○○】 Crystalと数値型

5 min read

📖【Crystalと○○】コンテンツ一覧

Crystal の数値の扱いは、パフォーマンス等の兼ね合いからでしょうか、通常利用される数値は固定長の整数型や浮動小数点数型のオブジェクトです。

データ長によって異なる型が用意されていたり整数型が符号有無で別れていたりと、C言語を齧ったことがある方にとっては馴染みの深い考え方だと思いますが、固定長整数の桁溢れ等を考慮する必要があるため、整数がどれだけ大きくなろうとも Integer 型が全て面倒を見てくれる Ruby に慣れている方には少々注意が必要かもしれません。

他方、Crystal の世界では全てのデータはオブジェクトであり、Java でいう「プリミティブ型」のようなデータ型は存在しません。例えば、1 + 0.5 という加算式も、実際には Int32(32bit符号付き整数)型のオブジェクトである 1 のインスタンスメソッド + に、引数として Float64(64bit浮動小数点数)型のオブジェクトである 0.5 を渡して実行することで実現されています。このような考え方は Ruby に慣れ親しんでいる方には比較的受け入易いのではないでしょうか。

数値型の継承関係

  • Number(数値)
    • Int(整数)
      • Int8(8bit符号付き整数)
      • Int16(16bit符号付き整数)
      • Int32(32bit符号付き整数)
      • Int64(64bit符号付き整数)
      • Int128(128bit符号付き整数)❗️
      • UInt8(8bit符号無し整数)
      • UInt16(16bit符号無し整数)
      • UInt32(32bit符号無し整数)
      • UInt64(64bit符号無し整数)
      • UInt128(128bit符号無し整数)❗️
      • BigInt(多倍長整数)
    • Float(浮動小数点数)
      • Float32(32bit浮動小数点数)
      • Float64(64bit浮動小数点数)
      • BigFloat(多倍長浮動小数点数)
    • BigDecimal(多倍長10進数)
    • BigRational(多倍長有理数)
  • Comprex(複素数)

「TODO: eventually update to literals once UInt128 bit support is finished」といったAPIリファレンスの記述を見る限り、v1.0.0時点では128bit長整数型(Int128 / UInt128)が完全にはサポートされていないようです。
実用の問題になることはほぼありませんが、心配であればこれらのサポートが完了するまでは、固定長整数型を使用する際は64bit長までにしておく方が良いかもしれません。

Number

複素数を除く全ての数値型の基底となる型で、四則演算やゼロの概念、他の数値との大小比較など、数値として基本的に持つ機能が定義されています。

Number 型は抽象型のため、直接インスタンス化はできません。

Int

全ての整数型の基底となる型で、Number 型で定義されたメソッドを整数向けにオーバーライドしたり、ビット演算など整数特有の機能が定義されています。

Int 型も抽象型のため、直接インスタンス化はできません。

Int〜

固定長の符号付き整数を表す型で、「〜」の部分にそれぞれビット長である 8, 16, 32, 64, 128が入る5つの型が存在します。

データ長が N bitの符号付き整数型が表現可能な整数値 i の範囲は -2^{N-1}<=i<=2^{N-1}-1 です。

Type MIN MAX
Int8 -128 127
Int16 -32,768 32,767
Int32 -2,147,483,648 2,147,483,647
Int64 -9,223,372,036,854,775,808 9,223,372,036,854,775,807
Int128 -170,141,183,460,469,231,731,687,303,715,884,105,728 170,141,183,460,469,231,731,687,303,715,884,105,727

計算結果がこれらの範囲を超える(下回る)値を示すような場合、実行時に OverflowError が発生するため注意が必要です。

Int32::MAX + 1
#=> Unhandled exception: Arithmetic overflow (OverflowError)

UInt〜

固定長の符号無し整数を表す型で、「〜」の部分にそれぞれビット長である 8, 16, 32, 64, 128が入る5つの型が存在します。

データ長が N bitの符号無し整数型が表現可能な整数値 i の範囲は 0<=i<=2^N-1 です。

Type MIN MAX
Int8 0 255
Int16 0 65,535
Int32 0 4,294,967,295
Int64 0 18,446,744,073,709,551,615
Int128 0 340,282,366,920,938,463,463,374,607,431,768,211,455

計算結果がこれらの範囲を超える(下回る)値を示すような場合に、OverflowError が発生するのは符号付き整数型の場合と同様です。

UInt32::MAX + 1
#=> Unhandled exception: Arithmetic overflow (OverflowError)

BigInt

GMP ライブラリを利用した多倍長整数を表す型です。

仕様上の上限は一応あるようですが、とりあえず 2^{1000000} (2の100万乘、301,030桁)くらいの数値は計算できたので、よほどのことがない限り上限値が実用上の制約になることはないものと思います。

2^{10000000} (2の1千万乘)も計算はできたようですが、結果の出力中にMacがフリーズしました。おそらく、300万桁超えの文字列を作る処理が重すぎたのではないかと。

Float

全ての浮動小数点数型の基底となる型です、Number 型で定義されたメソッドを浮動小数点数向けにオーバーライドしたり、一部特有の機能が定義されています。

Float 型も抽象型のため、直接インスタンス化はできません。

Float〜

「〜」の部分にビット長である32, 64が入る2つの型が存在し、それぞれ、IEEE 754で標準化されたbinary32(単精度浮動小数点数)、binary64(倍精度不動少数点数)を扱います。

BigFloat

GMP ライブラリを利用した多倍長浮動小数点数を表す型です。

BigDecimal

ある整数値(V)と、小数点以下の桁数(S)を指定することで、任意精度の符号付き10進数(V*10^{-S})を表す型です。

BigDecimalFloat と同じく主に少数を扱う型ですが、わざわざこうした仕組みが必要な理由は、Float 型(IEEE 754で標準化された浮動小数点数)では表現できない値が存在するためで、身近なところでは 0.1 などもそうした値の1つです。

一般的な利用では問題にならないレベルの誤差ですが、厳密な数値計算が必要な場面では、BigDecimal が必要になるかもしれません。

BigRational

GMP ライブラリを利用した多倍長有理数を表す型です。

まぁ要するに、分子と分母を指定して、分数を扱える型だと思ってほぼ間違いありません。

例えば、1 / 3 などは、0.3333333.... となり通常の IntFloat では表現できませんが、BigRational 型であれば BigRational.new(1, 3) として厳密に扱うことができます。

Complex

虚数 i を含む複素数を扱う型です。

数値を扱う型の中で、唯一 Number 型を継承していませんが、Number 系統の型との四則演算が定義されており、他の数値型との計算がある程度可能となっています。

また、複素数に特有の操作として、実数部/虚数部を個別に取得したり、共役複素数や位相を取得するメソッドなどが定義されています。

今回のまとめ

  • Crystal で一般的に扱う数値は固定長の整数/浮動小数点数型
  • データ長や符号の有無で型の使い分けが必要
  • 多倍長の数値型や複素数型が用意されている