A few weeks ago I posted a question to stackoverflow.
May be it was not right decision and I should ask it here. It would be great if you let me now, why progression and ranges are not possible for BigDecimal
, if they not. And if it is possible, then my proposal is to add BigDecimalProgression, to be able to write something like (a..b step c)
, where a
, b
and c
are instances of BigDecimal class.
P.S.: Here is a sample code, how I’ve implemented it in my project:
/**
* Returns a progression that goes over the same range with the given step.
*/
infix fun ClosedRange<BigDecimal>.step(step: BigDecimal): BigDecimalProgression {
if (step <= BigDecimal.ZERO) throw IllegalArgumentException("Step must be positive, was: $step.")
return BigDecimalProgression.fromClosedRange(start, endInclusive, step)
}
/**
* Returns a progression that goes over the same range with the given step.
*/
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`.
*/
open class BigDecimalProgression
internal constructor(start: BigDecimal, endInclusive: BigDecimal, step: BigDecimal)
: Iterable<BigDecimal> {
init {
if (step == BigDecimal.ZERO) throw IllegalArgumentException("Step must be non-zero")
}
/**
* The first element in the progression.
*/
val first: BigDecimal = start
/**
* The last element in the progression.
*/
val last: BigDecimal = getProgressionLastElement(start, endInclusive, step)
/**
* The step of the progression.
*/
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?) =
other is BigDecimalProgression && (isEmpty() && other.isEmpty() ||
first == other.first && last == other.last && step == other.step)
override fun hashCode() = if (isEmpty()) -1 else (31 * (31 * first.hashCode() + last.hashCode()) + step.hashCode())
override fun toString() = if (step > BigDecimal.ZERO) "$first..$last step $step" else "$first downTo $last step ${-step}"
private 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 IllegalArgumentException("Step is zero.")
}
}
companion object {
/**
* Creates IntProgression 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.
*/
fun fromClosedRange(rangeStart: BigDecimal, rangeEnd: BigDecimal, step: BigDecimal): BigDecimalProgression = BigDecimalProgression(rangeStart, rangeEnd, step)
}
}
/** An iterator over a sequence of values of type `BigDecimal`. */
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.
*/
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 NoSuchElementException()
hasNext = false
}
else {
next += step
}
return value
}
}