8000 Merge pull request #9155 from cahilltr/issue-12073 · scala/scala@4674f45 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4674f45

Browse files
authored
Merge pull request #9155 from cahilltr/issue-12073
Fix BigDecimal.Range for some very small step sizes
2 parents 9990ec0 + b2c2f35 commit 4674f45

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

src/library/scala/collection/immutable/NumericRange.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,18 @@ object NumericRange {
340340
// Jump in three pieces:
341341
// * start to -1 or 1, whichever is closer (waypointA)
342342
// * one step, which will take us at least to 0 (ends at waypointB)
343+
// * (except with really small numbers)
343344
// * there to the end
344345
val negone = num.fromInt(-1)
345346
val startlim = if (posStep) negone else one
346-
val startdiff = num.minus(startlim, start)
347+
//Use start value if the start value is closer to zero than startlim
348+
// * e.g. .5 is closer to zero than 1 and -.5 is closer to zero than -1
349+
val startdiff = {
350+
if ((posStep && num.lt(startlim, start)) || (!posStep && num.gt(startlim, start)))
351+
start
352+
else
353+
num.minus(startlim, start)
354+
}
347355
val startq = check(num.quot(startdiff, step))
348356
val waypointA = if (startq == zero) start else num.plus(start, num.times(startq, step))
349357
val waypointB = num.plus(waypointA, step)

test/junit/scala/collection/immutable/NumericRangeTest.scala

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,47 @@ class NumericRangeTest {
8888
assertFalse(NumericRange.inclusive(Long.MaxValue, Int.MaxValue.toLong, -1).isEmpty)
8989
assertTrue(NumericRange(Long.MaxValue, Long.MaxValue, -1).isEmpty)
9090
}
91-
}
91+
92+
@Test
93+
def smallIncrementCount: Unit = {
94+
case class TestRange(start: BigDecimal, end: BigDecimal, step: BigDecimal, inclusive: Boolean = false)
95+
def foldListIncrement(rangeTest: TestRange): List[BigDecimal] = {
96+
List.unfold(rangeTest. start) { prec =>
97+
Option.when(
98+
if (rangeTest.step > 0)
99+
prec < rangeTest.end
100+
else
101+
prec > rangeTest.end
102+
)(prec -> (prec + rangeTest.step))
103+
} ::: (if (rangeTest.inclusive) List(rangeTest.end) else List.empty[BigDecimal])
104+
}
105+
106+
def createRangeFromRangeTest(rangeTest: TestRange) =
107+
if (rangeTest.inclusive)
108+
Range.BigDecimal.inclusive(rangeTest.start, rangeTest.end, rangeTest.step)
109+
else
110+
Range.BigDecimal(rangeTest.start, rangeTest.end, rangeTest.step)
111+
112+
def negate(v: BigDecimal) = v.*(BigDecimal(-1))
113+
def double(v: BigDecimal) = v.*(BigDecimal(2))
114+
def negateDouble(v: BigDecimal) = negate(double(v))
115+
116+
val inclusiveValue = BigDecimal(1E-34)
117+
118+
List[TestRange](
119+
TestRange(BigDecimal(-2E-34), BigDecimal(1E-64), BigDecimal(1E-34)), //Negative to positive Range, positive step, exclusive
120+
TestRange(negateDouble(inclusiveValue), inclusiveValue, inclusiveValue, inclusive = true), //Negative to positive Range, positive step, inclusive
121+
TestRange(BigDecimal(1E-64), BigDecimal(-2E-34), BigDecimal(-1E-34)), //Positive to negative range, negative step, exclusive
122+
TestRange(inclusiveValue, negateDouble(inclusiveValue), negate(inclusiveValue), inclusive = true), //Positive to negative range, negative step, inclusive
123+
TestRange(BigDecimal(1E-64), BigDecimal(2E-34), BigDecimal(1E-34)), //Positive to positive, positive step, exclusive
124+
TestRange(inclusiveValue, double(inclusiveValue), inclusiveValue, inclusive = true), //Positive to positive, positive step, inclusive
125+
TestRange(BigDecimal(2E-34), BigDecimal(1E-64), BigDecimal(-1E-34)), //Positive to positive, negative step, exclusive
126+
TestRange(double(inclusiveValue), inclusiveValue, negate(inclusiveValue), inclusive = true), //Positive to positive, negative step, inclusive
127+
TestRange(BigDecimal(-1E-64), BigDecimal(-2E-34), BigDecimal(-1E-34)), //Negative to negative, negative step, exclusive
128+
TestRange(negate(inclusiveValue), negateDouble(inclusiveValue), negate(inclusiveValue), inclusive = true), //Negative to negative, negative step, inclusive
129+
TestRange(BigDecimal(-2E-34), BigDecimal(-1E-64), BigDecimal(1E-34)), //Negative to negative, positive step, exclusive
130+
TestRange(negateDouble(inclusiveValue), negate(inclusiveValue), inclusiveValue), //Negative to negative, positive step, inclusive
131+
TestRange(BigDecimal(9.474), BigDecimal(49.474), BigDecimal(1)) //BigDecimal in "large" increments
132+
).foreach(tr => assertEquals(foldListIncrement(tr).length, createRangeFromRangeTest(tr).length))
133+
}
134+
}

0 commit comments

Comments
 (0)
0