aherbert commented on code in PR #335:
URL: https://github.com/apache/commons-math/pull/335#discussion_r4352187441


##########
commons-math-legacy-core/src/main/java/org/apache/commons/math4/legacy/core/IntegerSequence.java:
##########
@@ -354,7 +378,7 @@ public boolean hasNext() {
         @Override
         public Integer next() {
             if (canIncrement(0)) {

Review Comment:
   Call `canIncrement()`



##########
commons-math-legacy-core/src/main/java/org/apache/commons/math4/legacy/core/IntegerSequence.java:
##########
@@ -276,7 +295,7 @@ public int getMaximalCount() {
          * @return the current count.
          */
         public int getCount() {
-            return count;
+            return (int) count;

Review Comment:
   This should be documented as returning the current count, or `maximalCount` 
if the sequence has exhausted the configured range. This would match the 
behaviour of the value passed to the callback when the sequence is exhausted.
   
   Then fix the return. Using a 32-bit truncation of a long can return nonsense 
results (see comment on `increment(int)`.



##########
commons-math-legacy-core/src/main/java/org/apache/commons/math4/legacy/core/IntegerSequence.java:
##########
@@ -89,15 +90,16 @@ public static class Range implements Iterable<Integer> {
          * @param max Last value of the range that satisfies the above
          * construction rule.
          * @param step Increment.
+         * @throws ZeroException if {@code step} is zero
          */
         public Range(int start,
                      int max,
                      int step) {
             this.start = start;
             this.max = max;
-            this.step = step;
+            this.step = Incrementor.checkIncrement(step);
 
-            final int s = (max - start) / step + 1;
+            final int s = (max - start) / this.step + 1;
             this.size = s < 0 ? 0 : s;

Review Comment:
   This will be negative if (max - start) overflows a positive integer. I think 
in this case the result should be set at Integer.MAX_VALUE not 0. 



##########
commons-math-legacy-core/src/main/java/org/apache/commons/math4/legacy/core/IntegerSequence.java:
##########
@@ -319,7 +343,7 @@ public void increment(int nTimes) throws 
MaxCountExceededException {
                 throw new NotStrictlyPositiveException(nTimes);
             }
 
-            count += nTimes * increment;
+            count += (long) nTimes * increment;

Review Comment:
   This is existing strange behaviour in the IntegerSequence. It updates the 
member count then checks if any more are allowed. The purpose is to allow 
multiple increments when at least 1 increment is possible, and then check if 
multiple have exhausted the sequence to trigger the callback. But the sequence 
does not actually check if even 1 increment is possible. I would be inclined to 
refactor `canIncrement` to not call `canincrement(1)` but to directly check the 
current count:
   ```java
   public boolean canIncrement() {
       // Adjust as required for your new inclusive parameter
       return increment < 0 ?
           count > maximalCount :
           count < maximalCount;
   }
   ```
   This method can be called before any modification of the count member. This 
prevents successive calls to `increment(int)` from increasing the count far 
above the maximum allowed.
   
   This is how broken the counter is:
   ```java
   IntegerSequence.Incrementor inc =
       IntegerSequence.Incrementor
           .create()
           .withIncrement(1 << 30)
           .withStart(0)
           .withMaximalCount(1 << 30)
           .withCallback(i -> {});
   for (int i = 0; i < 10; i++) {
       inc.increment(1);
       System.out.println(inc.getCount());
   }
   ```
   prints:
   ```
   1073741824
   -2147483648
   -1073741824
   0
   1073741824
   -2147483648
   -1073741824
   0
   1073741824
   -2147483648
   ```
   
   By changing the count to a `long` we will not get this behaviour any more. 
It will just keep incrementing the long. A request for the count using 
`getCount` will use the 32-bit truncation of the long, and possibly return 0 or 
a negative value for a positive integer sequence depending on where the long 
count has reached.
   



##########
commons-math-legacy-core/src/main/java/org/apache/commons/math4/legacy/core/IntegerSequence.java:
##########
@@ -89,15 +90,16 @@ public static class Range implements Iterable<Integer> {
          * @param max Last value of the range that satisfies the above
          * construction rule.
          * @param step Increment.
+         * @throws ZeroException if {@code step} is zero
          */
         public Range(int start,
                      int max,
                      int step) {
             this.start = start;
             this.max = max;
-            this.step = step;
+            this.step = Incrementor.checkIncrement(step);

Review Comment:
   I think we need more validation here. The step should be appropriately 
signed to match the sign of the difference (max - start). Otherwise you get 
stupid behaviour:
   ```java
   IntegerSequence.Incrementor inc =
       IntegerSequence.Incrementor
           .create()
           .withStart(0)
           .withMaximalCount(1)
           .withIncrement(-1)
           .withCallback(i -> {});
   for (int i = 0; i < 10; i++) {
       inc.increment(1);
       System.out.println(inc.getCount());
   }
   ```
   prints
   ```
   -1
   -2
   -3
   -4
   -5
   -6
   -7
   -8
   -9
   -10
   ```
   Without the callback which ignores the sequence exhaustion then this raises 
an exception immediately as the count is updated to -1 and the check to test 
for a negative increment if the count is above the maximal count fails.



##########
commons-math-legacy-core/src/main/java/org/apache/commons/math4/legacy/core/IntegerSequence.java:
##########


Review Comment:
   This should be documented to return a positive value in [0, 
Integer.MAX_VALUE]. It should be noted that the size may be larger than this if 
the range between the maximalCount and the start cannot be represented as a 
positive integer.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to