6.17. kink/NUM¶
6.17.1. type num¶
`num` is a floating point decimal number.
A `num` value consists of (Mantissa, Scale). The number represented by the `num` value is Mantissa * (10 ** (-Scale)). Here, `Mantissa` and `Scale` are signed integer numbers.
The runtime must at least support the range [-(2**95), (2**95) - 1] for `Mantissa`, and the range [-(2**7), (2**7) - 1] for `Scale`. Exceeding these limits may result in overflow or underflow.
Note: the Kink runtime on the JVM supports [-(2**2048 - 1), 2**2048 - 1] for `Mantissa`, and [-(2**15), (2**15)-1] for `Scale`.
Infinity, NaN, signed zeros are not supported.
Equality
There are multiple representations for one number. For example, 420 can be represented as (Mantissa=420, Scale=0), (Mantissa=42000, Scale=2) or (Mantissa=42, Scale=-1) and so on. They are treated as equal by == (op_eq) operator:
:NUM.require_from('kink/')
stdout.print_line((420 == 420.00).repr) # => true
stdout.print_line((420 == NUM.new(42 (-1))).repr) # => true
Bit operations
Bit operations take only int `num` values as operands. Nonnegative int `num` values are treated as if infinite 0 bits precede. Negative int `num` values are treated as two's complement with infinite preceding 1 bits.
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` returns `Mantissa` of `Num`.
The result is an int `num`.
Example
stdout.print_line(123.45.mantissa.repr) # => 12345
6.17.1.2. Num.scale¶
`scale` returns `Scale` of `Num`.
The result is an int `num`.
Example
stdout.print_line(123.45.scale.repr) # => 2
6.17.1.3. Num.int?¶
`int?` returns whether `Num` is an integer.
A `num` is an integer when `Scale` is zero.
Example
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¶
`+` operator, or `op_add` method, returns the sum of `X` and `Y`.
`Scale` of the result will be max(X.scale, Y.scale).
Precondition
`Y` must be a `num` value.
Example
: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¶
The binary `-` operator, or `op_sub` method, returns the difference of `X` and `Y`.
`Scale` of the result will be max(X.scale, Y.scale).
Precondition
`Y` must be a `num` value.
Example
:Diff <- 1.234 - 0.12
stdout.print_line(Diff.repr) # => 1.114
stdout.print_line(Diff.scale.repr) # => 3
6.17.1.6. - X¶
The unary `-` operator, or `op_minus` method, flips the sign of `X`.
Example
stdout.print_line((-42).repr) # => (-42)
stdout.print_line((-(-42)).repr) # => 42
stdout.print_line((-0).repr) # => 0
6.17.1.7. X * Y¶
`*` operator, or `op_mul` method, returns the production of `X` and `Y`.
`Scale` of the result will be X.scale + Y.scale.
Precondition
`Y` must be a `num` value.
Example
: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¶
`/` operator, or `op_div` method, makes a `num_div` value of (Dividend=X, Divisor=Y).
See kink/NUM_DIV for how to get a number from the `num_div` value.
Preconditions
`Y` must be a `num` value.
`Y` must not be equal to 0.
Example
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¶
`//` operator, or `op_intdiv` method, performs integral division, and returns the quotient.
Q = X // Y and R = X % Y will suffice the following conditions.
• Q * Y + R = X
• 0 <= R < Y.abs
• Q.scale = 0
• R.scale = X.scale
The rule above is equivalent to DIV and MOD of R6RS Scheme. See:
http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_sec_11.7.3.1
Precondition
`Y` must be a `num` value.
`Y` must not be equal to 0.
Example
: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¶
`%` operator, or `op_rem` method, performs integral division, and returns the remainder.
See X // Y for details.
Precondition
`Y` must be a `num` value.
`Y` must not be equal to 0.
6.17.1.11. X | Y¶
`|` operator, or `op_or` method, performs bit OR operation for `X` and `Y`.
The result will be an int `num`.
Preconditions
`X` must be an int `num`.
`Y` must be an int `num`.
6.17.1.12. X ^ Y¶
`^` operator, or `op_xor` method, performs bit XOR operation for `X` and `Y`.
The result will be an int `num`.
Preconditions
`X` must be an int `num`.
`Y` must be an int `num`.
6.17.1.13. X & Y¶
`&` operator, or `op_and` method, performs bit AND operation for `X` and `Y`.
The result will be an int `num`.
Preconditions
`X` must be an int `num`.
`Y` must be an int `num`.
6.17.1.14. ~ Num¶
`~` operator, or `op_not` method, performs bit NOT operation `Num`.
Preconditions
`Num` must be an int `num`.
6.17.1.15. Num << Bit_count¶
`<<` operator, or `op_shl` method, performs bit SHIFT-LEFT operation for `Num`.
If `Bit_count` is positive, `Num` is shifted `Bit_count` bits toward left.
If `Bit_count` is negative, `Num` is shifted (-Bit_count) bits toward right. The least significant (-Bit_count) bits are discarded.
If `Bit_count` is zero, `Num` is returned.
The result will be an int `num`.
Preconditions
`Num` must be an int `num`.
`Bit_count` must be an int `num`.
6.17.1.16. Num >> Bit_count¶
`>>` operator, or `op_shr` method, performs bit SHIFT-RIGHT operation for `Num`.
If `Bit_count` is positive, `Num` is shifted `Bit_count` bits toward right. The least significant `Bit_count` bits are discarded.
If `Bit_count` is negative, `Num` is shited (-Bit_count) bits toward left.
If `Bit_count` is zero, `Num` is returned.
The result will be an int `num`.
Preconditions
`Num` must be an int `num`.
`Bit_count` must be an int `num`.
6.17.1.17. X == Y¶
`==` operator, or `op_eq` method, returns whether the numbers are equal, irrespective of scales of them.
Precondition
`Y` must be a `num` value.
Example
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¶
`<=` operator, or `op_le` method, returns whether `X` is numerically smaller than or equal to `Y`.
Precondition
`Y` must be a `num` value.
Example
: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` returns a `num_div` value of (Dividend=Num, Divisor=1).
See kink/NUM_DIV for how to get a number from the `num_div` value.
Example
stdout.print_line(1.2345.round.floor(2).repr) # => 1.23
6.17.1.20. Num.abs¶
`abs` returns the absolute value of `Num`
If `Num` is nonnegative, `abs` returns `Num`. If `Num` is negative, `abs` returns (-Num).
Example
stdout.print_line(42.abs.repr) # => 42
stdout.print_line((-42).abs.repr) # => 42
6.17.1.21. Num.times¶
`times` returns an `iter` from 0 (inclusive), to `Num` (exclusive), incrementing 1 for each element.
Preconditions
`Num` must be an int `num`.
`Num` must be greater than or equal to 0.
Example
5.times.each{(:N)
stdout.print_line(N.repr)
}
# Output:
# 0
# 1
# 2
# 3
# 4
6.17.1.22. Num.up¶
`up` returns an infinite `iter` from `Num`, incrementing 1 for each element.
Example
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` returns an infinite `iter` from `Num`, decrementing 1 for each element.
Example
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` returns a `str` representation of `Num`, which is intended to be used in UI messages.
The optional parameter $show_config takes a function which takes a `num_show_config` value as an arg. `show` passes a `num_show_config` value to $show_config to configure the output.
Example:
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` is usually called from Str.format.
Example:
stdout.print_line('{} {%04x}'.format(42 255))
# => 42 00ff
For details of the output and the configuration, see type num_show_config.
6.17.1.25. Num.repr¶
`repr` returns a `str` such as "1.2500", "(-42)" or "(num mantissa=1 scale=-10)".
6.17.2. NUM.is?(Val)¶
`is?` returns whether `Val` is a `num` value.
6.17.3. NUM.new(Mantissa Scale)¶
`new` makes a `num` value with given `Mantissa` and `Scale`.
Preconditions
`Mantissa` must be an int `num`.
`Scale` must be an int `num`.
`Mantissa` and `Scale` must not exceed the limits of the runtime.
Example
:NUM.require_from('kink/')
stdout.print_line(NUM.new(12345 2).repr) # => 123.45
6.17.4. NUM.parse_int(Str ...[$config={}])¶
`parse_int` parses an int num from `Str`.
Config methods:
• C.radix(Radix): default = 10
• C.on_success($success): default = VAL.identity
• C.on_error($error): default = a fun which raises an exception
If `Str` is accepted by the syntax, `parse_int` tail-calls $success with the `num` value of the parsed integer.
If `Str` is not accepted by the syntax, `parse_int` tail-calls $error with no arg.
Syntax
The string representation is comprised of the two parts:
• Sign: '-', '+', or empty
• Digits: 1 or more digits of the numeral system of `Radix`.
Digits from 0 to 9 are represented by characters '0' to '9'.
Digits from 10 to 35 are represented by characters either 'A' to 'Z', or 'a' to 'z'.
Preconditions
`Str` must be a `str` value.
`Radix` must be an int `num` within [2, 36].
$success must take an int `num`.
$error must take no arg.
Example
: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)
Example
: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` parses a decimal number from `Str`.
Config methods:
• C.on_success($success): default = VAL.identity
• C.on_error($error): default = a fun which raises an exception
If `Str` is accepted by the syntax, `parse_decimal` tail-calls $success with the parsed `num` value. `Scale` of the result `num` will be the count of digits after `.`.
If `Str` is not accepted by the syntax, `parse_decimal` tail-calls $error with no arg.
Syntax
Regex: [+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)
Preconditions
`Str` must be a `str` value.
$success must take a `num` value.
$error must take no arg.
Example
: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)
Example
: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. type num_show_config¶
`num_show_config` is a subtype of `show_config` (see kink/STR), which is used to configure the output of Num.show.
Results of Num.show are categorized into two cases.
1) When `Scale` of the `num` is less than or equal to 0
In this case, the output will be “{sign}{grouped_padded_integral_digits}”.
2) When `Scale` of the `num` is greater than 0
In this case the radix must be 10, and the output will be “{sign}{grouped_padded_integral_digits}{decimal_sep}{fractional_digits}”.
Part: {sign}
If the `num` is less than 0, {sign} part is the negative sign mark set by `minus_sign` method.
If the `num` is greater than or equal to 0, {sign} part is the non-negative sign mark set by `plus_sign` method.
Part: {grouped_padded_integral_digits}
Firstly, the integral part of the `num` is converted to digits with the radix set by `radix` method. 0-9 and a-z characters are used as digits.
Secondly, "0" is padded to the left of the digits in order that the number of digits in this part is greater than or equal to the minimum number set by `pad_zero` method.
Finally, the digits are grouped using the group length set by `group_len`, and the grouping separator set by `group_sep` method is inserted between groups.
Part: {decimal_sep}
The mark set by `decimal_sep` method.
Part: {fractional_digits}
The decimal digits of the fractional part of the `num`.
The trailing zeros are not omitted, thus the length of the part is always equal to `Scale` of the `num`.
6.17.6.1. C.locale(Locale)¶
`locale` imports configuration of the specified locale.
`locale` configures `decimal_sep` and `group_sep`.
If `locale` method is not called, Num.show does not use any locale information. So, even if you want to use the runtime default locale, you must call `locale` method explicitly.
Precondition
`Locale` must be a `locale`.
Example
: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` configures the output of Num.show method using `Spec` string.
Preconditions
`Spec` must be a `str` value.
`Spec` must be a conjunction of the following fields.
Plus sign field: "+"
Uses "+" as the non-negative sign.
Grouping field: ","
Uses 3 as the grouping length.
Padding field: "0{Min_int_digits}"
Uses Min_int_digits as the minimum number of digits in the integral part.
{Min_int_digits} must be 1 or more decimal digits which represents a positive int `num`.
Binary field: "b"
Uses 2 as the radix.
Octal field: "o"
Uses 8 as the radix.
Decimal field: "d"
Uses 10 as the radix.
Headecimal field: "x"
Uses 16 as the radix.
Examples
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` sets `Plus_sign` as the sign of non-negative numbers.
The default value is an empty `str` "".
Precondition
`Plus_sign` must be a `str` value.
Example
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` sets `Minus_sign` as the sign of negative numbers.
The default value is "-".
Precondition
`Minus_sign` must be a `str` value.
Example
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` sets `Group_sep` as the digit grouping separator.
The default value is ",".
Precondition
`Group_sep` must be a `str` value.
Example
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` sets `Group_len` as the length of digits groups.
The default value is the plus infinity. Thus, by default, the grouping separator is not displayed.
Precondition
Group_len must be an int num bigger than or equal to 1
Example
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` sets `Decimal_sep` as the separator between the integral part and the fractional part.
Precondition
Decimal_sep must be a str
Example
stdout.print_line(12345.6789.show{(:S)
S.decimal_sep(' . ')
})
# => 12345 . 6789
6.17.6.8. C.pad_zero(Min_int_digits)¶
`pad_zero` sets `Min_int_digits` as the minimum number of the integral part to be output.
The default value is 1.
Precondition
`Min_int_digits` must be an int `num` greater than or equal to 1
Example
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` sets `Radix` as the radix of the result of `show` method.
The default value is 10.
Preconditions
`Radix` must be an int `num` in the range [2, 36].
If the `num` value which is shown is not an integer, `Radix` must be 10.
Example
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