Ideal Reality

興味の赴くままに

SwiftのDecimal(string:)がどれだけ使えるか試してみた

SwiftのDecimal型には、小数の精度が落ちないようにするために文字列からDecimalのインスタンスを生成するイニシャライザがあります。

僕が公開しているRPN Anywhereという電卓アプリではDecimal型を利用して計算しているのですが、コピペ機能を実装したくてどの程度文字列を整形してからDecimal型のイニシャライザに与えればいいか知りたかったので調べました。

Contents
スポンサーリンク

結論

先に結論を言うと

  • 扱えるのは一般的な有理数と指数表記(eを使った10のべき乗表記)のみ
  • 不正な文字がある場合、それ以前の文字列だけで評価される

です。

特に、コンマがあるとそれ以降の数字が無視されるのは致命的で、コピペの値をそのまま渡すのには使えないね。

なので、ユーザーの入力からDecimal型を生成するには整形してからにしましょう。

実験

$ swift -v
Apple Swift version 4.2.1 (swiftlang-1000.11.42 clang-1000.11.45.1)

Swiftのバージョンは4.2.1。

Macのターミナル上でswiftコマンドを実行し、対話的なインターフェイスを使って実験しました。

自然数

> print( Decimal(string: "3")! ) 
3

問題なく扱えます。当たり前。

小数点

> print( Decimal(string: "3.14159")! ) 
3.14159

もちろん扱えます。

> print( Decimal(string: "3.141.59")! ) 
3.141

意味のわからない2個目の小数点は不正なので、それ以降は無視されます

指数表記

> print( Decimal(string: "3.14159e3")! ) 
3141.59

これも問題なし

指数表記(小数)

> print( Decimal(string: "3.14159e0.5")! )
3.14159

これはやってくれない

指数表記(数字がない)

> print( Decimal(string: "3.14159e")! ) 
3.14159

記載がない場合は指数部が0になるのかな?

まあ結果はeを書いてない時と同じだ。

指数表記(複数)

> print( Decimal(string: "3.14159e3e2")! ) 
3141.59

変な書き方だけど、と解釈できないわけじゃないので

だけど、この場合2個目のeは不正で、それ以降の文字列は無視される。

符号

> print( Decimal(string: "+1")! ) 
1
> print( Decimal(string: "-1")! ) 
-1

まあ使えるでしょうな

符号だけ

> print( Decimal(string: "+")! ) 
0
> print( Decimal(string: "-")! ) 
0

エラーにならず0になる

符号が重なる

> print( Decimal(string: "++1")! )
0
> print( Decimal(string: "--1")! ) 
0
> print( Decimal(string: "++")! ) 
0
> print( Decimal(string: "--")! ) 
0

2個目の符号が不正でそれ以降が無視されるから、符号だけの場合と同じ動作になるみたい

指数表記 + 符号

> print( Decimal(string: "3.14159e+3")! ) 
3141.59
> print( Decimal(string: "3.14159e-3")! ) 
0.00314159
> print( Decimal(string: "3.14159e-")! ) 
3.14159
> print( Decimal(string: "3.14159e--3")! ) 
3.14159

今までの結果を踏まえると、まあ当然こうなるわな

スペース

> print( Decimal(string: "123 456 789")! ) 
123

スペースは不正な文字。

> print( Decimal(string: " 123")! ) 
123

ただ、先頭にスペースが入るのはちゃんと無視されるみたい

コンマ

print( Decimal(string: "123,456,789")! ) 
123

これもダメ。文書とかで表記されてるのをDecimalに入れるには整形しないといけないね。

アルファベット

> print( Decimal(string: "a") )
nil

まあ当たり前だね

> print( Decimal(string: "e")! )
0

指数表記のeだと思われてる?

演算

> print( Decimal(string: "1+2")! )
1
> print( Decimal(string: "1-2")! ) 
1
> print( Decimal(string: "1*2")! ) 
1
> print( Decimal(string: "1/2")! ) 
1
> print( Decimal(string: "2^2")! ) 
2
> print( Decimal(string: "5%3")! ) 
5

まあやってくれないだろうね。

それぞれをDecimal型のインスタンスにしてから普通にプログラム内で計算しろって話ですもんね。

お金

> print( Decimal(string: "¥120") )  
nil
> print( Decimal(string: "$1") )
nil

もちろんダメだ。

スポンサーリンク

結論は先に書いてある

のでここに書くことはない。

スポンサーリンク

コメント

投稿されたコメントはありません

名前

メールアドレス(任意)

コメント

関連する投稿

iOS13でViewController上部の隙間をなくす

NO IMAGE

SwiftUIでUISwipeGestureRecognizerを使ってスワイプを検出する

iOS14のUIDatePickerのデザインをカスタマイズする

SwiftUIでステータスバーの色を変える方法4つ

[SwiftUI]EnvironmentObjectをウィンドウごとに別々のインスタンスにしたい

[SwiftUI]List内のButtonやLinkのデザインをNavigationLinkっぽくする方法