为什么 Kotlin 没有十进制数?
Why Kotlin doesn't have a Decimal Progression?
最近我遇到了一个用小数步长迭代十进制数的问题,我想知道为什么 Kotlin 只有 Int
、Long
和 Char
.
我知道,十进制数字可能会有一些警告。但还是。我们只想有一个开始 BigDecimal
数字,结束 BigDecimal
数字,然后用 BigDecimal
步骤遍历它们。
Q: So, why there is no any progressions for not integer numbers? Thank you.
P.S.: 下面是一个可能实现的示例代码(我获取了 Int 的源代码并适应了 BigDecimal
):
/**
* Returns a progression that goes over the same range with the given step.
*/
public infix fun BigDecimalProgression.step(step: BigDecimal): BigDecimalProgression {
if (step <= java.math.BigDecimal.ZERO) throw IllegalArgumentException("Step must be positive, was: $step.")
return BigDecimalProgression.fromClosedRange(first, last, if (this.step > java.math.BigDecimal.ZERO) step else -step)
}
/**
* A progression of values of type `BigDecimal`.
*/
public open class BigDecimalProgression
internal constructor
(
start: BigDecimal,
endInclusive: BigDecimal,
step: BigDecimal
) : Iterable<BigDecimal> {
init {
if (step == BigDecimal.ZERO) throw kotlin.IllegalArgumentException("Step must be non-zero")
}
/**
* The first element in the progression.
*/
public val first: BigDecimal = start
/**
* The last element in the progression.
*/
public val last: BigDecimal = getProgressionLastElement(start, endInclusive, step)
/**
* The step of the progression.
*/
public val step: BigDecimal = step
override fun iterator(): BigDecimalIterator = BigDecimalProgressionIterator(first, last, step)
/** Checks if the progression is empty. */
public open fun isEmpty(): Boolean = if (step > BigDecimal.ZERO) first > last else first < last
override fun equals(other: Any?): Boolean =
other is BigDecimalProgression && (isEmpty() && other.isEmpty() ||
first == other.first && last == other.last && step == other.step)
override fun hashCode(): Int =
if (isEmpty()) -1 else (31 * (31 * first.hashCode() + last.hashCode()) + step.hashCode())
override fun toString(): String = if (step > BigDecimal.ZERO) "$first..$last step $step" else "$first downTo $last step ${-step}"
companion object {
/**
* Creates BigDecimalProgression within the specified bounds of a closed range.
* The progression starts with the [rangeStart] value and goes toward the [rangeEnd] value not excluding it, with the specified [step].
* In order to go backwards the [step] must be negative.
*/
public fun fromClosedRange(rangeStart: BigDecimal, rangeEnd: BigDecimal, step: BigDecimal): BigDecimalProgression = BigDecimalProgression(rangeStart, rangeEnd, step)
}
}
fun getProgressionLastElement(start: BigDecimal, end: BigDecimal, step: BigDecimal): BigDecimal {
if (step > BigDecimal.ZERO) {
return start + BigDecimal(((end - start) / step).toInt()) * step
} else if (step < BigDecimal.ZERO) {
return start - BigDecimal(((start - end) / -step).toInt()) * -step
} else {
throw kotlin.IllegalArgumentException("Step is zero.")
}
}
/** An iterator over a sequence of values of type `BigDecimal`. */
public abstract class BigDecimalIterator : Iterator<BigDecimal> {
override final fun next() = nextBigDecimal()
/** Returns the next value in the sequence without boxing. */
public abstract fun nextBigDecimal(): BigDecimal
}
/**
* An iterator over a progression of values of type `BigDecimal`.
* @property step the number by which the value is incremented on each step.
*/
internal class BigDecimalProgressionIterator(first: BigDecimal, last: BigDecimal, val step: BigDecimal) : BigDecimalIterator() {
private val finalElement = last
private var hasNext: Boolean = if (step > BigDecimal.ZERO) first <= last else first >= last
private var next = if (hasNext) first else finalElement
override fun hasNext(): Boolean = hasNext
override fun nextBigDecimal(): BigDecimal {
val value = next
if (value >= finalElement) {
if (!hasNext) throw kotlin.NoSuchElementException()
hasNext = false
}
else {
next += step
}
return value
}
}
正如在 documentation 中所说的范围:
Floating point numbers (Double, Float) do not define their rangeTo
operator, and the one provided by the standard library for generic
Comparable types is used instead:
public operator fun <T: Comparable<T>> T.rangeTo(that: T): ClosedRange<T>
The range returned by this function cannot be used for iteration. You
will have to use some other kind of loop since you can't use ranges.
他们只是没有定义。
最近我遇到了一个用小数步长迭代十进制数的问题,我想知道为什么 Kotlin 只有 Int
、Long
和 Char
.
我知道,十进制数字可能会有一些警告。但还是。我们只想有一个开始 BigDecimal
数字,结束 BigDecimal
数字,然后用 BigDecimal
步骤遍历它们。
Q: So, why there is no any progressions for not integer numbers? Thank you.
P.S.: 下面是一个可能实现的示例代码(我获取了 Int 的源代码并适应了 BigDecimal
):
/**
* Returns a progression that goes over the same range with the given step.
*/
public infix fun BigDecimalProgression.step(step: BigDecimal): BigDecimalProgression {
if (step <= java.math.BigDecimal.ZERO) throw IllegalArgumentException("Step must be positive, was: $step.")
return BigDecimalProgression.fromClosedRange(first, last, if (this.step > java.math.BigDecimal.ZERO) step else -step)
}
/**
* A progression of values of type `BigDecimal`.
*/
public open class BigDecimalProgression
internal constructor
(
start: BigDecimal,
endInclusive: BigDecimal,
step: BigDecimal
) : Iterable<BigDecimal> {
init {
if (step == BigDecimal.ZERO) throw kotlin.IllegalArgumentException("Step must be non-zero")
}
/**
* The first element in the progression.
*/
public val first: BigDecimal = start
/**
* The last element in the progression.
*/
public val last: BigDecimal = getProgressionLastElement(start, endInclusive, step)
/**
* The step of the progression.
*/
public val step: BigDecimal = step
override fun iterator(): BigDecimalIterator = BigDecimalProgressionIterator(first, last, step)
/** Checks if the progression is empty. */
public open fun isEmpty(): Boolean = if (step > BigDecimal.ZERO) first > last else first < last
override fun equals(other: Any?): Boolean =
other is BigDecimalProgression && (isEmpty() && other.isEmpty() ||
first == other.first && last == other.last && step == other.step)
override fun hashCode(): Int =
if (isEmpty()) -1 else (31 * (31 * first.hashCode() + last.hashCode()) + step.hashCode())
override fun toString(): String = if (step > BigDecimal.ZERO) "$first..$last step $step" else "$first downTo $last step ${-step}"
companion object {
/**
* Creates BigDecimalProgression within the specified bounds of a closed range.
* The progression starts with the [rangeStart] value and goes toward the [rangeEnd] value not excluding it, with the specified [step].
* In order to go backwards the [step] must be negative.
*/
public fun fromClosedRange(rangeStart: BigDecimal, rangeEnd: BigDecimal, step: BigDecimal): BigDecimalProgression = BigDecimalProgression(rangeStart, rangeEnd, step)
}
}
fun getProgressionLastElement(start: BigDecimal, end: BigDecimal, step: BigDecimal): BigDecimal {
if (step > BigDecimal.ZERO) {
return start + BigDecimal(((end - start) / step).toInt()) * step
} else if (step < BigDecimal.ZERO) {
return start - BigDecimal(((start - end) / -step).toInt()) * -step
} else {
throw kotlin.IllegalArgumentException("Step is zero.")
}
}
/** An iterator over a sequence of values of type `BigDecimal`. */
public abstract class BigDecimalIterator : Iterator<BigDecimal> {
override final fun next() = nextBigDecimal()
/** Returns the next value in the sequence without boxing. */
public abstract fun nextBigDecimal(): BigDecimal
}
/**
* An iterator over a progression of values of type `BigDecimal`.
* @property step the number by which the value is incremented on each step.
*/
internal class BigDecimalProgressionIterator(first: BigDecimal, last: BigDecimal, val step: BigDecimal) : BigDecimalIterator() {
private val finalElement = last
private var hasNext: Boolean = if (step > BigDecimal.ZERO) first <= last else first >= last
private var next = if (hasNext) first else finalElement
override fun hasNext(): Boolean = hasNext
override fun nextBigDecimal(): BigDecimal {
val value = next
if (value >= finalElement) {
if (!hasNext) throw kotlin.NoSuchElementException()
hasNext = false
}
else {
next += step
}
return value
}
}
正如在 documentation 中所说的范围:
Floating point numbers (Double, Float) do not define their rangeTo operator, and the one provided by the standard library for generic Comparable types is used instead:
public operator fun <T: Comparable<T>> T.rangeTo(that: T): ClosedRange<T>
The range returned by this function cannot be used for iteration. You will have to use some other kind of loop since you can't use ranges.
他们只是没有定义。