長い文字列をNSDecimalNumberに変換するとおしりが0になる
なにかの金額を入力する画面などで、ユーザーに数字を入力してもらうUIを作ることがある。金額なので、NSDecimalNumber
で受けることになる。このとき大きな数字を入力すると、入力とは違う値になることがある。*1
NSDecimalNumber(string: "999999999999999999999999999999999999999").stringValue // => "999999999999999999999999999999999999990"
これよりも長い文字列を入力すると、0
が続く。
NSDecimalNumber(string: "9999999999999999999999999999999999999999").stringValue // => "9999999999999999999999999999999999999900"
これは、NSDecimalNumber
の内部表現による制限である。NSDecimalNumber
は、128bitの符合なし整数と32bitの符合つき整数の組で表現されている。(下の定義では_mantissa
と_exponent
。)
struct NSDecimal { var _exponent: Int32 var _length: UInt32 var _isNegative: UInt32 var _isCompact: UInt32 var _reserved: UInt32 var _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16) init() init(_exponent _exponent: Int32, _length _length: UInt32, _isNegative _isNegative: UInt32, _isCompact _isCompact: UInt32, _reserved _reserved: UInt32, _mantissa _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16)) }
例えば、123.45であれば、12345 * 10^-2として、12345と-2の組で表現する。*2
つまり、_mantissa
に対応する値は、128bitで表現できる範囲でなくてはならない。
Rubyで試してみると999999999999999999999999999999999999999
を表現するには130bit必要とのことなので、128bitでは足りずに切り捨てられたということがわかる。
> 999999999999999999999999999999999999999.bit_length => 130 > 99999999999999999999999999999999999999.bit_length => 127
つまり、999999999999999999999999999999999999990
というのは、
_mantissa
=9999999999999999999999999999999999999
_exponent
=1
になっているはず。