6.17. kink/NUM¶
6.17.1. num型¶
numは十進の浮動小数点数である。
num値は(Mantissa, Scale)から構成される。このnum値は、Mantissa * (10 ** (-Scale))という数値を表現する。
ランタイムは最低でも、Mantissaについては[-(2**95), (2**95) - 1]の範囲を、Scaleについては[-(2**7), (2**7) - 1]の範囲をサポートしなければならない。これらの制限を超えると、オーバーフロー、またはアンダーフローが起きる可能性がある。
注釈: JVM上のKinkランタイムは、Mantissaについて[-(2**2048 - 1), 2**2048 - 1]を、Scaleについて[-(2**15), (2**15)-1]をサポートする。
無限大、NaN, 符号付きゼロはサポートされない。
同値性
ひとつの数値について複数の表現があり得る。たとえば、420は(Mantissa=420, Scale=0), (Mantissa=42000, Scale=2), (Mantissa=42, Scale=-1)などのように表現される。これらの値は、==演算子(op_eqメソッド)で同値として扱われる:
:NUM.require_from('kink/')
stdout.print_line((420 == 420.00).repr) # => true
stdout.print_line((420 == NUM.new(42 (-1))).repr) # => true
ビット操作
ビット操作は整数のnum値だけをオペランドとして取る。非負のnum値は、0のビットが無限に先行しているように扱われる。負のnum値は、1のビットが無限に先行する、2の補数表現として扱われる。
stdout.print_line((~ 0b_1010).repr) # => (-11)
stdout.print_line('{%b}'.format(~ 0b_1010)) # => -1011
stdout.print_line('{%b}'.format(~ 0b_1010 & 0b_1111_1111)) # => 11110101
6.17.1.1. Num.mantissa¶
mantissaはNumのMantissaを戻す。
結果は整数のnum値である。
例
stdout.print_line(123.45.mantissa.repr) # => 12345
6.17.1.2. Num.scale¶
scaleはNumのScaleを戻す。
結果は整数のnum値である。
例
stdout.print_line(123.45.scale.repr) # => 2
6.17.1.3. Num.int?¶
int?はNumが整数かどうかを戻す。
num値が整数であるのは、Scaleが0であるときである。
例
stdout.print_line(120.int?.repr) # => true
stdout.print_line(120.0.int?.repr) # => false
stdout.print_line(3.14.int?.repr) # => false
6.17.1.4. X + Y¶
+演算子、またはop_addメソッドは、XとYの和を戻す。
結果のScaleはmax(X.scale, Y.scale)である。
事前条件
Yはnum値でなければならない。
例
:Sum <- 1.234 + 0.12
stdout.print_line(Sum.repr) # => 1.354
stdout.print_line(Sum.scale.repr) # => 3
6.17.1.5. X - Y¶
二項の - 演算子、またはop_subメソッドは、XとYの差を戻す。
結果のScaleはmax(X.scale, Y.scale)である。
事前条件
Yはnum値でなければならない。
例
:Diff <- 1.234 - 0.12
stdout.print_line(Diff.repr) # => 1.114
stdout.print_line(Diff.scale.repr) # => 3
6.17.1.6. - X¶
単項の - 演算子、またはop_minusメソッドは、Xの符号を反転する。
例
stdout.print_line((-42).repr) # => (-42)
stdout.print_line((-(-42)).repr) # => 42
stdout.print_line((-0).repr) # => 0
6.17.1.7. X * Y¶
*演算子、またはop_mulメソッドは、XとYの積を戻す。
結果のScaleは X.scale + Y.scale である。
事前条件
Yはnum値でなければならない。
例
:Prod <- 1.2 * 3.45
stdout.print_line(Prod.repr) # => 4.140
stdout.print_line(Prod.scale.repr) # => 3
6.17.1.8. X / Y¶
/演算子、またはop_divメソッドは、(Dividend=X, Divisor=Y)からなるnum_div値を戻す。
num_div値からどのように値を取り出すかについては、kink/num_DIVを見よ。
事前条件
Yはnum値でなければならない。
Yは0と等しくてはならない。
例
stdout.print_line((10 / 3).floor(3).repr) # => 3.333
stdout.print_line((10 / 3).ceil(3).repr) # => 3.334
6.17.1.9. X // Y¶
//演算子、またはop_intdivメソッドは、整数除算をおこなって、商を戻す。
Q = X // Y と R = X % Y は、次の条件を満たす。
• Q * Y + R = X
• 0 <= R < Y.abs
• Q.scale = 0
• R.scale = X.scale
上記の規則はR6Rs SchemeのDIVとMODと同等だ。参照:
http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_sec_11.7.3.1
事前条件
Yはnum値でなければならない。
Yは0と等しくてはならない。
例
:attempt_intdiv <- {(:X :Y)
:Q = X // Y
:R = X % Y
stdout.print_line('{} // {} = {}, remainder: {}'.format(X.repr Y.repr Q.repr R.repr))
}
attempt_intdiv(10 3)
# => 10 // 3 = 3, remainder: 1
attempt_intdiv(10 (-3))
# => 10 // (-3) = (-3), remainder: 1
attempt_intdiv((-10) 3)
# => (-10) // 3 = (-4), remainder: 2
attempt_intdiv((-10) (-3))
# => (-10) // (-3) = 4, remainder: 2
attempt_intdiv(10 1.5)
# => 10 // 1.5 = 6, remainder: 1.0
attempt_intdiv(5.5 3)
# => 5.5 // 3 = 1, remainder: 2.5
attempt_intdiv(5.5 1.5)
# => 5.5 // 1.5 = 3, remainder: 1.0
6.17.1.10. X % Y¶
%演算子、またはop_remメソッドは、整数除算をおこなって、剰余を戻す。
詳細は X // Y を見よ。
事前条件
Yはnum値でなければならない。
Yは0と等しくてはならない。
6.17.1.11. X | Y¶
| 演算子、またはop_orメソッドは、XとYに対してビットOR演算をおこなう。
結果は整数のnum値である。
事前条件
Xは整数のnum値でなければならない。
Yは整数のnum値でなければならない。
6.17.1.12. X ^ Y¶
^ 演算子、またはop_xorメソッドは、XとYに対してビットXOR演算をおこなう。
結果は整数のnum値である。
事前条件
Xは整数のnum値でなければならない。
Yは整数のnum値でなければならない。
6.17.1.13. X & Y¶
& 演算子、またはop_andメソッドは、XとYに対してビットAND演算をおこなう。
結果は整数のnum値である。
事前条件
Xは整数のnum値でなければならない。
Yは整数のnum値でなければならない。
6.17.1.14. ~ Num¶
~ 演算子、またはop_notメソッドは、Numに対してビットNOT演算をおこなう。
事前条件
Numは整数のnum値でなければならない。
6.17.1.15. Num << Bit_count¶
<< 演算子、またはop_shlメソッドは、Numに対してビット左シフト演算をおこなう。
Bit_countが正のとき、NumはBit_countビットだけ左にシフトされる。
Bit_countが負のとき、Numは(-Bit_count)ビットだけ右にシフトされる。下位(-Bit_count)ビットは捨てられる。
Bit_countが0のときは、Numが戻る。
結果は整数のnum値である。
事前条件
Numは整数のnum値でなければならない。
Bit_countは整数のnum値でなければならない。
6.17.1.16. Num >> Bit_count¶
>> 演算子、またはop_shrメソッドは、Numに対してビット右シフト演算をおこなう。
Bit_countが正のとき、NumはBit_countビットだけ右にシフトされる。下位Bit_countビットは捨てられる。
Bit_countが負のとき、Numは(-Bit_count)ビットだけ左にシフトされる。
Bit_countが0のときは、Numが戻る。
結果は整数のnum値である。
事前条件
Numは整数のnum値でなければならない。
Bit_countは整数のnum値でなければならない。
6.17.1.17. X == Y¶
== 演算子、またはop_eqメソッドは、ふたつの数値が、Scaleを無視して等しいかどうかを戻す。
事前条件
Yはnum値でなければならない。
例
stdout.print_line((42 == 42.000).repr) # => true
stdout.print_line((42 != 42.000).repr) # => false
stdout.print_line((42 == 24).repr) # => false
stdout.print_line((42 != 24).repr) # => true
6.17.1.18. X <= Y¶
<= 演算子、またはop_leメソッドは、Xが数値的にY以下かどうかを戻す。
事前条件
Yはnum値でなければならない。
例
:compare <- {(:X :Y)
stdout.print_line('Lt?={} Le?={} Gt?={} Ge?={}'.format(
(X < Y).repr
(X <= Y).repr
(X > Y).repr
(X >= Y).repr))
}
compare(42 42.000) # => Lt?=false Le?=true Gt?=false Ge?=true
compare(42 84) # => Lt?=true Le?=true Gt?=false Ge?=false
compare(42 21) # => Lt?=false Le?=false Gt?=true Ge?=true
6.17.1.19. Num.round¶
roundは、(Dividend=Num, Divisor=1)からなるnum_div値を戻す。
num_div値からどのように値を取り出すかについては、kink/num_DIVを見よ。
例
stdout.print_line(1.2345.round.floor(2).repr) # => 1.23
6.17.1.20. Num.abs¶
absはNumの絶対値を戻す。
Numが非負の場合、absはNumを戻す。Numが負の場合、absは(-Num)を戻す。
例
stdout.print_line(42.abs.repr) # => 42
stdout.print_line((-42).abs.repr) # => 42
6.17.1.21. Num.times¶
timesは0から(包含的)、Numまで(排除的)へ、要素ごとに1ずつ増えるiterを戻す。
事前条件
Numは整数のnum値でなければならない。
Numは0以上でなければならない。
例
5.times.each{(:N)
stdout.print_line(N.repr)
}
# Output:
# 0
# 1
# 2
# 3
# 4
6.17.1.22. Num.up¶
upはNumから始まって、要素ごとに1ずつ増える無限長のiterを戻す。
例
0.5.up.take_front(5).each{(:N)
stdout.print_line(N.repr)
}
# Output:
# 0.5
# 1.5
# 2.5
# 3.5
# 4.5
6.17.1.23. Num.down¶
downはNumから始まって、要素ごとに1ずつ減る無限長のiterを戻す。
例
9.5.down.take_front(5).each{(:N)
stdout.print_line(N.repr)
}
# Output:
# 9.5
# 8.5
# 7.5
# 6.5
# 5.5
6.17.1.24. Num.show(...[$show_config={}])¶
showはNumの文字列表現をstr値として戻す。結果はUIメッセージに使うことが意図される。
省略可能パラメータ$show_configは、num_show_config型の値を取る関数を引数に取る。showはnum_show_config値を渡して$show_configを呼び出す。
例:
stdout.print_line(32767.show) # => 32767
stdout.print_line(32767.show{(:S) S.spec('x') }) # => 7fff
stdout.print_line(32767.show{(:S) S.radix(16) }) # => 7fff
stdout.print_line(32767.show{(:S) S.group_sep(3) }) # => 32,767
showは通常Str.formatから呼ばれる。
例:
stdout.print_line('{} {%04x}'.format(42 255))
# => 42 00ff
出力と設定の詳細についてはnum_show_config型を見よ。
6.17.1.25. Num.repr¶
reprは"1.2500", "(-42)", "(num mantissa=1 scale=-10)"のような文字列を戻す。
6.17.2. NUM.is?(Val)¶
is?はValがnum値であるかどうかを戻す。
6.17.3. NUM.new(Mantissa Scale)¶
newはMantissaとScaleから新しいnum値を作る
事前条件
Mantissaは整数のnum値でなければならない。
Scaleは整数のnum値でなければならない。
MantissaとScaleはランタイムの制限を超えてはならない。
例
:NUM.require_from('kink/')
stdout.print_line(NUM.new(12345 2).repr) # => 123.45
6.17.4. NUM.parse_int(Str ...[$config={}])¶
parse_intはStrをパースして整数のnum値を戻す。
コンフィグメソッド:
• C.radix(Radix): default = 10
• C.on_success($success): default = VAL.identity
• C.on_error($error): default = 例外を投げる関数
Strが文法に受け入れられる場合、parse_intはパースされた整数のnum値を渡して$successを末尾呼び出しする。
Strが文法に受け入れられない場合、parse_intは$errorを引数なしで末尾呼び出しする。
文法
文字列表現は次のふたつの部分からなる。
• Sign: '-', '+', または空
• Digits: 1桁以上のRadix進法の桁
0から9の桁は、'0'から'9'までの文字で表される。
10から35の桁は、'A'から'Z'、または'a'から'z'までの文字で表される。
事前条件
Strはstr値でなければならない。
Radixは[2, 36]の範囲の整数のnum値でなければならない。
$successは整数のnum値を取らなければならない。
$errorは引数を取らない関数でなければならない。
例
:NUM.require_from('kink/')
stdout.print_line(NUM.parse_int('42').repr) # => 42
stdout.print_line(NUM.parse_int('+42').repr) # => 42
stdout.print_line(NUM.parse_int('-42').repr) # => (-42)
stdout.print_line(NUM.parse_int('ff'){(:C) C.radix(16) }.repr) # => 255
stdout.print_line(NUM.parse_int('fF'){(:C) C.radix(16) }.repr) # => 255
stdout.print_line(NUM.parse_int('-ff'){(:C) C.radix(16) }.repr) # => (-255)
例
:NUM.require_from('kink/')
NUM.parse_int('42'){(:C)
C.on_success{(:N) stdout.print_line(N.repr) }
C.on_error{ stdout.print_line('not valid') }
}
# => 42
NUM.parse_int('*invalid*'){(:C)
C.on_success{(:N) stdout.print_line(N.repr) }
C.on_error{ stdout.print_line('not valid') }
}
# => not valid
6.17.5. NUM.parse_decimal(Str ...[$config={}])¶
parse_decimalはStrから十進数をパースする。
コンフィグメソッド:
• C.on_success($success): default = VAL.identity
• C.on_error($error): default = 例外を投げる関数
Strが文法に受け入れられる場合、parse_decimalはnum値を渡して$successを末尾呼び出しする。 `.` のあとの桁の個数が、結果のnum値のScaleになる。
Strが文法に受け入れられない場合、parse_decimalは引数なしで$errorを末尾呼び出しする。
文法
正規表現: [+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)
事前条件
Strはstr値でなければならない。
$successはnum値を取らなければならない。
$errorは引数を取らない関数でなければならない。
例
:NUM.require_from('kink/')
stdout.print_line(NUM.parse_decimal('1.2300').repr) # => 1.2300
stdout.print_line(NUM.parse_decimal('.387').repr) # => 0.387
stdout.print_line(NUM.parse_decimal('-42.').repr) # => (-42)
例
:NUM.require_from('kink/')
NUM.parse_decimal('3.14'){(:C)
C.on_success{(:N) stdout.print_line(N.repr) }
C.on_error{ stdout.print_line('not valid') }
}
# => 3.14
NUM.parse_decimal('*invalid*'){(:C)
C.on_success{(:N) stdout.print_line(N.repr) }
C.on_error{ stdout.print_line('not valid') }
}
# => not valid
6.17.6. num_show_config型¶
num_show_configはshow_configの部分型(kink/STRを見よ)である。Num.showの出力を設定するのに使われる。
Num.showの結果はふたつのケースに分けられる。
1) num値のScaleが0以下の場合
この場合、出力は “{sign}{grouped_padded_integral_digits}” の形式になる。
2) num値のScaleが0より大きい場合
この場合、基数は10でなければならない。出力は “{sign}{grouped_padded_integral_digits}{decimal_sep}{fractional_digits}” の形式になる。
{sign} の部分
num値が0より小さいとき、{sign}の部分はminus_signメソッドで指定された負の符号になる。
num値が0以上のとき、{sign}の部分はplus_signメソッドで指定された非負の符号になる。
{grouped_padded_integral_digits} の部分
まず、num値の整数部分がradixで指定された基数で、0-9, a-zの桁に変換される。
つぎに、この部分の桁数が、pad_zeroメソッドで指定された最小値よりも少なくならないよう、桁の左側に0が埋められる。
最後に、group_lenで指定されたグループ長によって、桁がグループ化される。グループそれぞれの間には、group_sepで指定された区切り記号が挿入される。
{decimal_sep} の部分
decimal_sepメソッドで指定された記号。
{fractional_digits} の部分
num値の小数部分の十進の桁。
末尾の0は省略されない。したがって、この部分の長さは常にnum値のScaleと等しくなる。
6.17.6.1. C.locale(Locale)¶
localeメソッドを呼ぶと、指定されたロケールの設定を読み込む。
localeメソッドはdecimal_sepとgroup_sepを設定する。
localeが呼ばれなければ、Num.showはどのロケールの情報も使わない。したがって、ランタイムのデフォルトのロケールを使いたい場合でも、明示的にlocaleメソッドを呼ぶ必要がある。
事前条件
Localeはlocale型の値でなければならない。
例
:LOCALE.require_from('kink/')
:Shown <- 3776.24.show{(:S)
S.locale(LOCALE.default)
}
stdout.print_line(Shown)
# Output varies by the runtime default locale
6.17.6.2. C.spec(Spec)¶
specはNum.showの出力を、Spec文字列で指定する。
事前条件
Specはstr値でなければならない。
Specは以下に述べるフィールドをつなげたものでなければならない。
正の符号のフィールド: "+"
"+" を非負の符号として使う。
グルーピングフィールド: ","
グループ長として3を使う。
パディングフィールド: "0{Min_int_digits}"
Min_int_digitsを整数部分の最低限の桁数として使う。
{Min_int_digits}は1つ以上の十進の桁でなければならない。
二進フィールド: "b"
基数として2を使う。
八進フィールド: "o"
基数として8を使う。
十進フィールド: "d"
基数として10を使う。
十六進フィールド: "x"
基数として16を使う
例
stdout.print_line('{%+04f}'.format(255))
# => +00ff
stdout.print_line('{%,}'.format(12345.6789))
# => 12,345.6789
stdout.print_line('{%b}'.format(42))
# => 101010
stdout.print_line('{%o}'.format(42))
# => 52
stdout.print_line('{%d}'.format(42))
# => 42
stdout.print_line('{%x}'.format(42))
# => 2a
6.17.6.3. C.plus_sign(Plus_sign)¶
plus_signはPlus_signを非負の数の符号として設定する。
デフォルト値は空の文字列 "" である。
事前条件
Plus_signはstr値でなければならない。
例
stdout.print_line(42.show{(:S)
S.plus_sign('+')
})
# => +42
stdout.print_line(0.show{(:S)
S.plus_sign('+')
})
# => +0
stdout.print_line((-10).show{(:S)
S.plus_sign('+')
})
# => -10
6.17.6.4. C.minus_sign(Minus_sign)¶
minus_signはMinus_signを負の数の符号として設定する。
デフォルト値は "-" である。
事前条件
Minus_signはstr値でなければならない。
例
stdout.print_line((-10).show{(:S)
S.minus_sign('minus ')
})
# => minus 10
stdout.print_line(42.show{(:S)
S.minus_sign('minus ')
})
# => 42
stdout.print_line(0.show{(:S)
S.minus_sign('minus ')
})
# => 0
6.17.6.5. C.group_sep(Group_sep)¶
group_sepはGroup_sepをグループ区切りとして設定する。
デフォルト値は "," である。
事前条件
Group_sepはstr値でなければならない。
例
stdout.print_line(12345.6789.show{(:S)
S.group_sep('_')
S.group_len(3)
})
# => 12_345.6789
stdout.print_line(37767.show{(:S)
S.group_sep('_')
S.group_len(2)
S.radix(16)
})
# => 7f_ff
6.17.6.6. C.group_len(Group_len)¶
group_lenはGroup_lenを桁グループの長さとして設定する。
デフォルト値は正の無限大である。つまり、デフォルトではグループ区切りは使われない。
事前条件
Group_lenは1以上の整数のnum値でなければならない。
例
stdout.print_line(12345.6789.show{(:S)
S.group_len(3)
})
# => 12,345.6789
6.17.6.7. C.decimal_sep(Decimal_sep)¶
decimal_sepはDecimal_sepを、整数部と小数部を区切る記号として設定する。
事前条件
Decimal_sepはstr値でなければならない。
例
stdout.print_line(12345.6789.show{(:S)
S.decimal_sep(' . ')
})
# => 12345 . 6789
6.17.6.8. C.pad_zero(Min_int_digits)¶
pad_zeroはMin_int_digitsを、出力される整数部分の桁数の最小値として設定する。
デフォルト値は1である。
事前条件
Min_int_digitsは1以上の整数のnum値でなければならない。
例
stdout.print_line(12345.6789.show{(:S)
S.pad_zero(8)
})
# => 00012345.6789
stdout.print_line((-42).show{(:S)
S.pad_zero(4)
})
# => -0042
stdout.print_line(255.show{(:S)
S.pad_zero(4)
S.radix(16)
})
# => 00ff
6.17.6.9. C.radix(Radix)¶
radixはRadixをshowメソッドの結果の基数として設定する。
デフォルト値は10である。
事前条件
Radixは[2, 36]の範囲内の整数のnum値でなければならない。
showメソッドを呼び出す対象のnum値が整数でないとき、Radixは10でなければならない。
例
stdout.print_line(255.show{(:S)
S.radix(2)
})
# => 11111111
stdout.print_line(255.show{(:S)
S.radix(16)
})
# => ff
stdout.print_line((-255).show{(:S)
S.radix(16)
})
# => -ff