Added sources from apache commons lang
This commit is contained in:
commit
dfcf4e96b9
11 changed files with 5689 additions and 0 deletions
32
.gitignore
vendored
Normal file
32
.gitignore
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
10
README.md
Normal file
10
README.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# SDM assigment 04
|
||||
|
||||
Classes come from [https://github.com/apache/commons-lang](https://github.com/apache/commons-lang)
|
||||
revision `770e72d2f78361b14f3fe27caea41e5977d3c638`
|
||||
|
||||
## Run Tests
|
||||
|
||||
```
|
||||
mvn clean test
|
||||
```
|
58
pom.xml
Normal file
58
pom.xml
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>sdm04</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.23.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.9.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.10.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.19.1</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-surefire-provider</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
379
src/main/java/ch/usi/inf/sdm/sdm04/CharRange.java
Normal file
379
src/main/java/ch/usi/inf/sdm/sdm04/CharRange.java
Normal file
|
@ -0,0 +1,379 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ch.usi.inf.sdm.sdm04;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A contiguous range of characters, optionally negated.
|
||||
*
|
||||
* <p>Instances are immutable.</p>
|
||||
*
|
||||
* <p>#ThreadSafe#</p>
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
// TODO: This is no longer public and will be removed later as CharSet is moved
|
||||
// to depend on Range.
|
||||
final class CharRange implements Iterable<Character>, Serializable {
|
||||
|
||||
/**
|
||||
* Required for serialization support. Lang version 2.0.
|
||||
*
|
||||
* @see Serializable
|
||||
*/
|
||||
private static final long serialVersionUID = 8270183163158333422L;
|
||||
|
||||
/**
|
||||
* The first character, inclusive, in the range.
|
||||
*/
|
||||
private final char start;
|
||||
|
||||
/**
|
||||
* The last character, inclusive, in the range.
|
||||
*/
|
||||
private final char end;
|
||||
|
||||
/**
|
||||
* True if the range is everything except the characters specified.
|
||||
*/
|
||||
private final boolean negated;
|
||||
|
||||
/**
|
||||
* Cached toString.
|
||||
*/
|
||||
private transient String iToString;
|
||||
|
||||
/**
|
||||
* Empty array.
|
||||
*/
|
||||
static final CharRange[] EMPTY_ARRAY = {};
|
||||
|
||||
/**
|
||||
* Constructs a {@link CharRange} over a set of characters,
|
||||
* optionally negating the range.
|
||||
*
|
||||
* <p>A negated range includes everything except that defined by the
|
||||
* start and end characters.</p>
|
||||
*
|
||||
* <p>If start and end are in the wrong order, they are reversed.
|
||||
* Thus {@code a-e} is the same as {@code e-a}.</p>
|
||||
*
|
||||
* @param start first character, inclusive, in this range
|
||||
* @param end last character, inclusive, in this range
|
||||
* @param negated true to express everything except the range
|
||||
*/
|
||||
private CharRange(char start, char end, final boolean negated) {
|
||||
if (start > end) {
|
||||
final char temp = start;
|
||||
start = end;
|
||||
end = temp;
|
||||
}
|
||||
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.negated = negated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link CharRange} over a single character.
|
||||
*
|
||||
* @param ch only character in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange is(final char ch) {
|
||||
return new CharRange(ch, ch, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a negated {@link CharRange} over a single character.
|
||||
*
|
||||
* <p>A negated range includes everything except that defined by the
|
||||
* single character.</p>
|
||||
*
|
||||
* @param ch only character in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange isNot(final char ch) {
|
||||
return new CharRange(ch, ch, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link CharRange} over a set of characters.
|
||||
*
|
||||
* <p>If start and end are in the wrong order, they are reversed.
|
||||
* Thus {@code a-e} is the same as {@code e-a}.</p>
|
||||
*
|
||||
* @param start first character, inclusive, in this range
|
||||
* @param end last character, inclusive, in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange isIn(final char start, final char end) {
|
||||
return new CharRange(start, end, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a negated {@link CharRange} over a set of characters.
|
||||
*
|
||||
* <p>A negated range includes everything except that defined by the
|
||||
* start and end characters.</p>
|
||||
*
|
||||
* <p>If start and end are in the wrong order, they are reversed.
|
||||
* Thus {@code a-e} is the same as {@code e-a}.</p>
|
||||
*
|
||||
* @param start first character, inclusive, in this range
|
||||
* @param end last character, inclusive, in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange isNotIn(final char start, final char end) {
|
||||
return new CharRange(start, end, true);
|
||||
}
|
||||
|
||||
// Accessors
|
||||
/**
|
||||
* Gets the start character for this character range.
|
||||
*
|
||||
* @return the start char (inclusive)
|
||||
*/
|
||||
public char getStart() {
|
||||
return this.start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the end character for this character range.
|
||||
*
|
||||
* @return the end char (inclusive)
|
||||
*/
|
||||
public char getEnd() {
|
||||
return this.end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this {@link CharRange} negated.
|
||||
*
|
||||
* <p>A negated range includes everything except that defined by the
|
||||
* start and end characters.</p>
|
||||
*
|
||||
* @return {@code true} if negated
|
||||
*/
|
||||
public boolean isNegated() {
|
||||
return negated;
|
||||
}
|
||||
|
||||
// Contains
|
||||
/**
|
||||
* Is the character specified contained in this range.
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return {@code true} if this range contains the input character
|
||||
*/
|
||||
public boolean contains(final char ch) {
|
||||
return (ch >= start && ch <= end) != negated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are all the characters of the passed in range contained in
|
||||
* this range.
|
||||
*
|
||||
* @param range the range to check against
|
||||
* @return {@code true} if this range entirely contains the input range
|
||||
* @throws NullPointerException if {@code null} input
|
||||
*/
|
||||
public boolean contains(final CharRange range) {
|
||||
Objects.requireNonNull(range, "range");
|
||||
if (negated) {
|
||||
if (range.negated) {
|
||||
return start >= range.start && end <= range.end;
|
||||
}
|
||||
return range.end < start || range.start > end;
|
||||
}
|
||||
if (range.negated) {
|
||||
return start == 0 && end == Character.MAX_VALUE;
|
||||
}
|
||||
return start <= range.start && end >= range.end;
|
||||
}
|
||||
|
||||
// Basics
|
||||
/**
|
||||
* Compares two CharRange objects, returning true if they represent
|
||||
* exactly the same range of characters defined in the same way.
|
||||
*
|
||||
* @param obj the object to compare to
|
||||
* @return true if equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof CharRange)) {
|
||||
return false;
|
||||
}
|
||||
final CharRange other = (CharRange) obj;
|
||||
return start == other.start && end == other.end && negated == other.negated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hashCode compatible with the equals method.
|
||||
*
|
||||
* @return a suitable hashCode
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 83 + start + 7 * end + (negated ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string representation of the character range.
|
||||
*
|
||||
* @return string representation of this range
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (iToString == null) {
|
||||
final StringBuilder buf = new StringBuilder(4);
|
||||
if (isNegated()) {
|
||||
buf.append('^');
|
||||
}
|
||||
buf.append(start);
|
||||
if (start != end) {
|
||||
buf.append('-');
|
||||
buf.append(end);
|
||||
}
|
||||
iToString = buf.toString();
|
||||
}
|
||||
return iToString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator which can be used to walk through the characters described by this range.
|
||||
*
|
||||
* <p>#NotThreadSafe# the iterator is not thread-safe</p>
|
||||
*
|
||||
* @return an iterator to the chars represented by this range
|
||||
* @since 2.5
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Character> iterator() {
|
||||
return new CharacterIterator(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Character {@link Iterator}.
|
||||
* <p>#NotThreadSafe#</p>
|
||||
*/
|
||||
private static class CharacterIterator implements Iterator<Character> {
|
||||
/**
|
||||
* The current character
|
||||
*/
|
||||
private char current;
|
||||
|
||||
private final CharRange range;
|
||||
private boolean hasNext;
|
||||
|
||||
/**
|
||||
* Constructs a new iterator for the character range.
|
||||
*
|
||||
* @param r The character range
|
||||
*/
|
||||
private CharacterIterator(final CharRange r) {
|
||||
range = r;
|
||||
hasNext = true;
|
||||
|
||||
if (range.negated) {
|
||||
if (range.start == 0) {
|
||||
if (range.end == Character.MAX_VALUE) {
|
||||
// This range is an empty set
|
||||
hasNext = false;
|
||||
} else {
|
||||
current = (char) (range.end + 1);
|
||||
}
|
||||
} else {
|
||||
current = 0;
|
||||
}
|
||||
} else {
|
||||
current = range.start;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the next character in the range.
|
||||
*/
|
||||
private void prepareNext() {
|
||||
if (range.negated) {
|
||||
if (current == Character.MAX_VALUE) {
|
||||
hasNext = false;
|
||||
} else if (current + 1 == range.start) {
|
||||
if (range.end == Character.MAX_VALUE) {
|
||||
hasNext = false;
|
||||
} else {
|
||||
current = (char) (range.end + 1);
|
||||
}
|
||||
} else {
|
||||
current = (char) (current + 1);
|
||||
}
|
||||
} else if (current < range.end) {
|
||||
current = (char) (current + 1);
|
||||
} else {
|
||||
hasNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the iterator not reached the end character yet?
|
||||
*
|
||||
* @return {@code true} if the iterator has yet to reach the character date
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next character in the iteration
|
||||
*
|
||||
* @return {@link Character} for the next character
|
||||
*/
|
||||
@Override
|
||||
public Character next() {
|
||||
if (!hasNext) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
final char cur = current;
|
||||
prepareNext();
|
||||
return Character.valueOf(cur);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always throws UnsupportedOperationException.
|
||||
*
|
||||
* @throws UnsupportedOperationException Always thrown.
|
||||
* @see Iterator#remove()
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
911
src/main/java/ch/usi/inf/sdm/sdm04/math/Fraction.java
Normal file
911
src/main/java/ch/usi/inf/sdm/sdm04/math/Fraction.java
Normal file
|
@ -0,0 +1,911 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ch.usi.inf.sdm.sdm04.math;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@link Fraction} is a {@link Number} implementation that
|
||||
* stores fractions accurately.
|
||||
*
|
||||
* <p>This class is immutable, and interoperable with most methods that accept
|
||||
* a {@link Number}.</p>
|
||||
*
|
||||
* <p>Note that this class is intended for common use cases, it is <i>int</i>
|
||||
* based and thus suffers from various overflow issues. For a BigInteger based
|
||||
* equivalent, please see the Commons Math BigFraction class.</p>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public final class Fraction extends Number implements Comparable<Fraction> {
|
||||
|
||||
/**
|
||||
* Required for serialization support. Lang version 2.0.
|
||||
*
|
||||
* @see java.io.Serializable
|
||||
*/
|
||||
private static final long serialVersionUID = 65382027393090L;
|
||||
|
||||
/**
|
||||
* {@link Fraction} representation of 0.
|
||||
*/
|
||||
public static final Fraction ZERO = new Fraction(0, 1);
|
||||
/**
|
||||
* {@link Fraction} representation of 1.
|
||||
*/
|
||||
public static final Fraction ONE = new Fraction(1, 1);
|
||||
/**
|
||||
* {@link Fraction} representation of 1/2.
|
||||
*/
|
||||
public static final Fraction ONE_HALF = new Fraction(1, 2);
|
||||
/**
|
||||
* {@link Fraction} representation of 1/3.
|
||||
*/
|
||||
public static final Fraction ONE_THIRD = new Fraction(1, 3);
|
||||
/**
|
||||
* {@link Fraction} representation of 2/3.
|
||||
*/
|
||||
public static final Fraction TWO_THIRDS = new Fraction(2, 3);
|
||||
/**
|
||||
* {@link Fraction} representation of 1/4.
|
||||
*/
|
||||
public static final Fraction ONE_QUARTER = new Fraction(1, 4);
|
||||
/**
|
||||
* {@link Fraction} representation of 2/4.
|
||||
*/
|
||||
public static final Fraction TWO_QUARTERS = new Fraction(2, 4);
|
||||
/**
|
||||
* {@link Fraction} representation of 3/4.
|
||||
*/
|
||||
public static final Fraction THREE_QUARTERS = new Fraction(3, 4);
|
||||
/**
|
||||
* {@link Fraction} representation of 1/5.
|
||||
*/
|
||||
public static final Fraction ONE_FIFTH = new Fraction(1, 5);
|
||||
/**
|
||||
* {@link Fraction} representation of 2/5.
|
||||
*/
|
||||
public static final Fraction TWO_FIFTHS = new Fraction(2, 5);
|
||||
/**
|
||||
* {@link Fraction} representation of 3/5.
|
||||
*/
|
||||
public static final Fraction THREE_FIFTHS = new Fraction(3, 5);
|
||||
/**
|
||||
* {@link Fraction} representation of 4/5.
|
||||
*/
|
||||
public static final Fraction FOUR_FIFTHS = new Fraction(4, 5);
|
||||
|
||||
|
||||
/**
|
||||
* The numerator number part of the fraction (the three in three sevenths).
|
||||
*/
|
||||
private final int numerator;
|
||||
/**
|
||||
* The denominator number part of the fraction (the seven in three sevenths).
|
||||
*/
|
||||
private final int denominator;
|
||||
|
||||
/**
|
||||
* Cached output hashCode (class is immutable).
|
||||
*/
|
||||
private transient int hashCode;
|
||||
/**
|
||||
* Cached output toString (class is immutable).
|
||||
*/
|
||||
private transient String toString;
|
||||
/**
|
||||
* Cached output toProperString (class is immutable).
|
||||
*/
|
||||
private transient String toProperString;
|
||||
|
||||
/**
|
||||
* Constructs a {@link Fraction} instance with the 2 parts
|
||||
* of a fraction Y/Z.
|
||||
*
|
||||
* @param numerator the numerator, for example the three in 'three sevenths'
|
||||
* @param denominator the denominator, for example the seven in 'three sevenths'
|
||||
*/
|
||||
private Fraction(final int numerator, final int denominator) {
|
||||
this.numerator = numerator;
|
||||
this.denominator = denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Fraction} instance with the 2 parts
|
||||
* of a fraction Y/Z.
|
||||
*
|
||||
* <p>Any negative signs are resolved to be on the numerator.</p>
|
||||
*
|
||||
* @param numerator the numerator, for example the three in 'three sevenths'
|
||||
* @param denominator the denominator, for example the seven in 'three sevenths'
|
||||
* @return a new fraction instance
|
||||
* @throws ArithmeticException if the denominator is {@code zero}
|
||||
* or the denominator is {@code negative} and the numerator is {@code Integer#MIN_VALUE}
|
||||
*/
|
||||
public static Fraction getFraction(int numerator, int denominator) {
|
||||
if (denominator == 0) {
|
||||
throw new ArithmeticException("The denominator must not be zero");
|
||||
}
|
||||
if (denominator < 0) {
|
||||
if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
|
||||
throw new ArithmeticException("overflow: can't negate");
|
||||
}
|
||||
numerator = -numerator;
|
||||
denominator = -denominator;
|
||||
}
|
||||
return new Fraction(numerator, denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Fraction} instance with the 3 parts
|
||||
* of a fraction X Y/Z.
|
||||
*
|
||||
* <p>The negative sign must be passed in on the whole number part.</p>
|
||||
*
|
||||
* @param whole the whole number, for example the one in 'one and three sevenths'
|
||||
* @param numerator the numerator, for example the three in 'one and three sevenths'
|
||||
* @param denominator the denominator, for example the seven in 'one and three sevenths'
|
||||
* @return a new fraction instance
|
||||
* @throws ArithmeticException if the denominator is {@code zero}
|
||||
* @throws ArithmeticException if the denominator is negative
|
||||
* @throws ArithmeticException if the numerator is negative
|
||||
* @throws ArithmeticException if the resulting numerator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public static Fraction getFraction(final int whole, final int numerator, final int denominator) {
|
||||
if (denominator == 0) {
|
||||
throw new ArithmeticException("The denominator must not be zero");
|
||||
}
|
||||
if (denominator < 0) {
|
||||
throw new ArithmeticException("The denominator must not be negative");
|
||||
}
|
||||
if (numerator < 0) {
|
||||
throw new ArithmeticException("The numerator must not be negative");
|
||||
}
|
||||
final long numeratorValue;
|
||||
if (whole < 0) {
|
||||
numeratorValue = whole * (long) denominator - numerator;
|
||||
} else {
|
||||
numeratorValue = whole * (long) denominator + numerator;
|
||||
}
|
||||
if (numeratorValue < Integer.MIN_VALUE || numeratorValue > Integer.MAX_VALUE) {
|
||||
throw new ArithmeticException("Numerator too large to represent as an Integer.");
|
||||
}
|
||||
return new Fraction((int) numeratorValue, denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reduced {@link Fraction} instance with the 2 parts
|
||||
* of a fraction Y/Z.
|
||||
*
|
||||
* <p>For example, if the input parameters represent 2/4, then the created
|
||||
* fraction will be 1/2.</p>
|
||||
*
|
||||
* <p>Any negative signs are resolved to be on the numerator.</p>
|
||||
*
|
||||
* @param numerator the numerator, for example the three in 'three sevenths'
|
||||
* @param denominator the denominator, for example the seven in 'three sevenths'
|
||||
* @return a new fraction instance, with the numerator and denominator reduced
|
||||
* @throws ArithmeticException if the denominator is {@code zero}
|
||||
*/
|
||||
public static Fraction getReducedFraction(int numerator, int denominator) {
|
||||
if (denominator == 0) {
|
||||
throw new ArithmeticException("The denominator must not be zero");
|
||||
}
|
||||
if (numerator == 0) {
|
||||
return ZERO; // normalize zero.
|
||||
}
|
||||
// allow 2^k/-2^31 as a valid fraction (where k>0)
|
||||
if (denominator == Integer.MIN_VALUE && (numerator & 1) == 0) {
|
||||
numerator /= 2;
|
||||
denominator /= 2;
|
||||
}
|
||||
if (denominator < 0) {
|
||||
if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
|
||||
throw new ArithmeticException("overflow: can't negate");
|
||||
}
|
||||
numerator = -numerator;
|
||||
denominator = -denominator;
|
||||
}
|
||||
// simplify fraction.
|
||||
final int gcd = greatestCommonDivisor(numerator, denominator);
|
||||
numerator /= gcd;
|
||||
denominator /= gcd;
|
||||
return new Fraction(numerator, denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Fraction} instance from a {@code double} value.
|
||||
*
|
||||
* <p>This method uses the <a href="https://web.archive.org/web/20210516065058/http%3A//archives.math.utk.edu/articles/atuyl/confrac/">
|
||||
* continued fraction algorithm</a>, computing a maximum of
|
||||
* 25 convergents and bounding the denominator by 10,000.</p>
|
||||
*
|
||||
* @param value the double value to convert
|
||||
* @return a new fraction instance that is close to the value
|
||||
* @throws ArithmeticException if {@code |value| > Integer.MAX_VALUE}
|
||||
* or {@code value = NaN}
|
||||
* @throws ArithmeticException if the calculated denominator is {@code zero}
|
||||
* @throws ArithmeticException if the algorithm does not converge
|
||||
*/
|
||||
public static Fraction getFraction(double value) {
|
||||
final int sign = value < 0 ? -1 : 1;
|
||||
value = Math.abs(value);
|
||||
if (value > Integer.MAX_VALUE || Double.isNaN(value)) {
|
||||
throw new ArithmeticException("The value must not be greater than Integer.MAX_VALUE or NaN");
|
||||
}
|
||||
final int wholeNumber = (int) value;
|
||||
value -= wholeNumber;
|
||||
|
||||
int numer0 = 0; // the pre-previous
|
||||
int denom0 = 1; // the pre-previous
|
||||
int numer1 = 1; // the previous
|
||||
int denom1 = 0; // the previous
|
||||
int numer2; // the current, setup in calculation
|
||||
int denom2; // the current, setup in calculation
|
||||
int a1 = (int) value;
|
||||
int a2;
|
||||
double x1 = 1;
|
||||
double x2;
|
||||
double y1 = value - a1;
|
||||
double y2;
|
||||
double delta1, delta2 = Double.MAX_VALUE;
|
||||
double fraction;
|
||||
int i = 1;
|
||||
do {
|
||||
delta1 = delta2;
|
||||
a2 = (int) (x1 / y1);
|
||||
x2 = y1;
|
||||
y2 = x1 - a2 * y1;
|
||||
numer2 = a1 * numer1 + numer0;
|
||||
denom2 = a1 * denom1 + denom0;
|
||||
fraction = (double) numer2 / (double) denom2;
|
||||
delta2 = Math.abs(value - fraction);
|
||||
a1 = a2;
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
numer0 = numer1;
|
||||
denom0 = denom1;
|
||||
numer1 = numer2;
|
||||
denom1 = denom2;
|
||||
i++;
|
||||
} while (delta1 > delta2 && denom2 <= 10000 && denom2 > 0 && i < 25);
|
||||
if (i == 25) {
|
||||
throw new ArithmeticException("Unable to convert double to fraction");
|
||||
}
|
||||
return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Fraction from a {@link String}.
|
||||
*
|
||||
* <p>The formats accepted are:</p>
|
||||
*
|
||||
* <ol>
|
||||
* <li>{@code double} String containing a dot</li>
|
||||
* <li>'X Y/Z'</li>
|
||||
* <li>'Y/Z'</li>
|
||||
* <li>'X' (a simple whole number)</li>
|
||||
* </ol>
|
||||
* <p>and a .</p>
|
||||
*
|
||||
* @param str the string to parse, must not be {@code null}
|
||||
* @return the new {@link Fraction} instance
|
||||
* @throws NullPointerException if the string is {@code null}
|
||||
* @throws NumberFormatException if the number format is invalid
|
||||
*/
|
||||
|
||||
public static Fraction getFraction(String str) {
|
||||
Objects.requireNonNull(str, "str");
|
||||
// parse double format
|
||||
int pos = str.indexOf('.');
|
||||
if (pos >= 0) {
|
||||
return getFraction(Double.parseDouble(str));
|
||||
}
|
||||
|
||||
// parse X Y/Z format
|
||||
pos = str.indexOf(' ');
|
||||
if (pos > 0) {
|
||||
final int whole = Integer.parseInt(str.substring(0, pos));
|
||||
str = str.substring(pos + 1);
|
||||
pos = str.indexOf('/');
|
||||
if (pos < 0) {
|
||||
throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z");
|
||||
}
|
||||
final int numer = Integer.parseInt(str.substring(0, pos));
|
||||
final int denom = Integer.parseInt(str.substring(pos + 1));
|
||||
return getFraction(whole, numer, denom);
|
||||
}
|
||||
|
||||
// parse Y/Z format
|
||||
pos = str.indexOf('/');
|
||||
if (pos < 0) {
|
||||
// simple whole number
|
||||
return getFraction(Integer.parseInt(str), 1);
|
||||
}
|
||||
final int numer = Integer.parseInt(str.substring(0, pos));
|
||||
final int denom = Integer.parseInt(str.substring(pos + 1));
|
||||
return getFraction(numer, denom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the numerator part of the fraction.
|
||||
*
|
||||
* <p>This method may return a value greater than the denominator, an
|
||||
* improper fraction, such as the seven in 7/4.</p>
|
||||
*
|
||||
* @return the numerator fraction part
|
||||
*/
|
||||
|
||||
public int getNumerator() {
|
||||
return numerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the denominator part of the fraction.
|
||||
*
|
||||
* @return the denominator fraction part
|
||||
*/
|
||||
public int getDenominator() {
|
||||
return denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proper numerator, always positive.
|
||||
*
|
||||
* <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
|
||||
* This method returns the 3 from the proper fraction.</p>
|
||||
*
|
||||
* <p>If the fraction is negative such as -7/4, it can be resolved into
|
||||
* -1 3/4, so this method returns the positive proper numerator, 3.</p>
|
||||
*
|
||||
* @return the numerator fraction part of a proper fraction, always positive
|
||||
*/
|
||||
public int getProperNumerator() {
|
||||
return Math.abs(numerator % denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proper whole part of the fraction.
|
||||
*
|
||||
* <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
|
||||
* This method returns the 1 from the proper fraction.</p>
|
||||
*
|
||||
* <p>If the fraction is negative such as -7/4, it can be resolved into
|
||||
* -1 3/4, so this method returns the positive whole part -1.</p>
|
||||
*
|
||||
* @return the whole fraction part of a proper fraction, that includes the sign
|
||||
*/
|
||||
public int getProperWhole() {
|
||||
return numerator / denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as an {@code int}. This returns the whole number
|
||||
* part of the fraction.
|
||||
*
|
||||
* @return the whole number fraction part
|
||||
*/
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return numerator / denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@code long}. This returns the whole number
|
||||
* part of the fraction.
|
||||
*
|
||||
* @return the whole number fraction part
|
||||
*/
|
||||
@Override
|
||||
public long longValue() {
|
||||
return (long) numerator / denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@code float}. This calculates the fraction
|
||||
* as the numerator divided by denominator.
|
||||
*
|
||||
* @return the fraction as a {@code float}
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return (float) numerator / (float) denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@code double}. This calculates the fraction
|
||||
* as the numerator divided by denominator.
|
||||
*
|
||||
* @return the fraction as a {@code double}
|
||||
*/
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return (double) numerator / (double) denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce the fraction to the smallest values for the numerator and
|
||||
* denominator, returning the result.
|
||||
*
|
||||
* <p>For example, if this fraction represents 2/4, then the result
|
||||
* will be 1/2.</p>
|
||||
*
|
||||
* @return a new reduced fraction instance, or this if no simplification possible
|
||||
*/
|
||||
public Fraction reduce() {
|
||||
if (numerator == 0) {
|
||||
return equals(ZERO) ? this : ZERO;
|
||||
}
|
||||
final int gcd = greatestCommonDivisor(Math.abs(numerator), denominator);
|
||||
if (gcd == 1) {
|
||||
return this;
|
||||
}
|
||||
return getFraction(numerator / gcd, denominator / gcd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a fraction that is the inverse (1/fraction) of this one.
|
||||
*
|
||||
* <p>The returned fraction is not reduced.</p>
|
||||
*
|
||||
* @return a new fraction instance with the numerator and denominator
|
||||
* inverted.
|
||||
* @throws ArithmeticException if the fraction represents zero.
|
||||
*/
|
||||
public Fraction invert() {
|
||||
if (numerator == 0) {
|
||||
throw new ArithmeticException("Unable to invert zero.");
|
||||
}
|
||||
if (numerator==Integer.MIN_VALUE) {
|
||||
throw new ArithmeticException("overflow: can't negate numerator");
|
||||
}
|
||||
if (numerator<0) {
|
||||
return new Fraction(-denominator, -numerator);
|
||||
}
|
||||
return new Fraction(denominator, numerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a fraction that is the negative (-fraction) of this one.
|
||||
*
|
||||
* <p>The returned fraction is not reduced.</p>
|
||||
*
|
||||
* @return a new fraction instance with the opposite signed numerator
|
||||
*/
|
||||
public Fraction negate() {
|
||||
// the positive range is one smaller than the negative range of an int.
|
||||
if (numerator==Integer.MIN_VALUE) {
|
||||
throw new ArithmeticException("overflow: too large to negate");
|
||||
}
|
||||
return new Fraction(-numerator, denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a fraction that is the positive equivalent of this one.
|
||||
* <p>More precisely: {@code (fraction >= 0 ? this : -fraction)}</p>
|
||||
*
|
||||
* <p>The returned fraction is not reduced.</p>
|
||||
*
|
||||
* @return {@code this} if it is positive, or a new positive fraction
|
||||
* instance with the opposite signed numerator
|
||||
*/
|
||||
public Fraction abs() {
|
||||
if (numerator >= 0) {
|
||||
return this;
|
||||
}
|
||||
return negate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a fraction that is raised to the passed in power.
|
||||
*
|
||||
* <p>The returned fraction is in reduced form.</p>
|
||||
*
|
||||
* @param power the power to raise the fraction to
|
||||
* @return {@code this} if the power is one, {@link #ONE} if the power
|
||||
* is zero (even if the fraction equals ZERO) or a new fraction instance
|
||||
* raised to the appropriate power
|
||||
* @throws ArithmeticException if the resulting numerator or denominator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public Fraction pow(final int power) {
|
||||
if (power == 1) {
|
||||
return this;
|
||||
}
|
||||
if (power == 0) {
|
||||
return ONE;
|
||||
}
|
||||
if (power < 0) {
|
||||
if (power == Integer.MIN_VALUE) { // MIN_VALUE can't be negated.
|
||||
return this.invert().pow(2).pow(-(power / 2));
|
||||
}
|
||||
return this.invert().pow(-power);
|
||||
}
|
||||
final Fraction f = this.multiplyBy(this);
|
||||
if (power % 2 == 0) { // if even...
|
||||
return f.pow(power / 2);
|
||||
}
|
||||
return f.pow(power / 2).multiplyBy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the greatest common divisor of the absolute value of
|
||||
* two numbers, using the "binary gcd" method which avoids
|
||||
* division and modulo operations. See Knuth 4.5.2 algorithm B.
|
||||
* This algorithm is due to Josef Stein (1961).
|
||||
*
|
||||
* @param u a non-zero number
|
||||
* @param v a non-zero number
|
||||
* @return the greatest common divisor, never zero
|
||||
*/
|
||||
private static int greatestCommonDivisor(int u, int v) {
|
||||
// From Commons Math:
|
||||
if (u == 0 || v == 0) {
|
||||
if (u == Integer.MIN_VALUE || v == Integer.MIN_VALUE) {
|
||||
throw new ArithmeticException("overflow: gcd is 2^31");
|
||||
}
|
||||
return Math.abs(u) + Math.abs(v);
|
||||
}
|
||||
// if either operand is abs 1, return 1:
|
||||
if (Math.abs(u) == 1 || Math.abs(v) == 1) {
|
||||
return 1;
|
||||
}
|
||||
// keep u and v negative, as negative integers range down to
|
||||
// -2^31, while positive numbers can only be as large as 2^31-1
|
||||
// (i.e. we can't necessarily negate a negative number without
|
||||
// overflow)
|
||||
if (u > 0) {
|
||||
u = -u;
|
||||
} // make u negative
|
||||
if (v > 0) {
|
||||
v = -v;
|
||||
} // make v negative
|
||||
// B1. [Find power of 2]
|
||||
int k = 0;
|
||||
while ((u & 1) == 0 && (v & 1) == 0 && k < 31) { // while u and v are both even...
|
||||
u /= 2;
|
||||
v /= 2;
|
||||
k++; // cast out twos.
|
||||
}
|
||||
if (k == 31) {
|
||||
throw new ArithmeticException("overflow: gcd is 2^31");
|
||||
}
|
||||
// B2. Initialize: u and v have been divided by 2^k and at least
|
||||
// one is odd.
|
||||
int t = (u & 1) == 1 ? v : -(u / 2)/* B3 */;
|
||||
// t negative: u was odd, v may be even (t replaces v)
|
||||
// t positive: u was even, v is odd (t replaces u)
|
||||
do {
|
||||
/* assert u<0 && v<0; */
|
||||
// B4/B3: cast out twos from t.
|
||||
while ((t & 1) == 0) { // while t is even.
|
||||
t /= 2; // cast out twos
|
||||
}
|
||||
// B5 [reset max(u,v)]
|
||||
if (t > 0) {
|
||||
u = -t;
|
||||
} else {
|
||||
v = t;
|
||||
}
|
||||
// B6/B3. at this point both u and v should be odd.
|
||||
t = (v - u) / 2;
|
||||
// |u| larger: t positive (replace u)
|
||||
// |v| larger: t negative (replace v)
|
||||
} while (t != 0);
|
||||
return -u * (1 << k); // gcd is u*2^k
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply two integers, checking for overflow.
|
||||
*
|
||||
* @param x a factor
|
||||
* @param y a factor
|
||||
* @return the product {@code x*y}
|
||||
* @throws ArithmeticException if the result can not be represented as
|
||||
* an int
|
||||
*/
|
||||
private static int mulAndCheck(final int x, final int y) {
|
||||
final long m = (long) x * (long) y;
|
||||
if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) {
|
||||
throw new ArithmeticException("overflow: mul");
|
||||
}
|
||||
return (int) m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply two non-negative integers, checking for overflow.
|
||||
*
|
||||
* @param x a non-negative factor
|
||||
* @param y a non-negative factor
|
||||
* @return the product {@code x*y}
|
||||
* @throws ArithmeticException if the result can not be represented as
|
||||
* an int
|
||||
*/
|
||||
private static int mulPosAndCheck(final int x, final int y) {
|
||||
/* assert x>=0 && y>=0; */
|
||||
final long m = (long) x * (long) y;
|
||||
if (m > Integer.MAX_VALUE) {
|
||||
throw new ArithmeticException("overflow: mulPos");
|
||||
}
|
||||
return (int) m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add two integers, checking for overflow.
|
||||
*
|
||||
* @param x an addend
|
||||
* @param y an addend
|
||||
* @return the sum {@code x+y}
|
||||
* @throws ArithmeticException if the result can not be represented as
|
||||
* an int
|
||||
*/
|
||||
private static int addAndCheck(final int x, final int y) {
|
||||
final long s = (long) x + (long) y;
|
||||
if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) {
|
||||
throw new ArithmeticException("overflow: add");
|
||||
}
|
||||
return (int) s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract two integers, checking for overflow.
|
||||
*
|
||||
* @param x the minuend
|
||||
* @param y the subtrahend
|
||||
* @return the difference {@code x-y}
|
||||
* @throws ArithmeticException if the result can not be represented as
|
||||
* an int
|
||||
*/
|
||||
private static int subAndCheck(final int x, final int y) {
|
||||
final long s = (long) x - (long) y;
|
||||
if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) {
|
||||
throw new ArithmeticException("overflow: add");
|
||||
}
|
||||
return (int) s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the value of this fraction to another, returning the result in reduced form.
|
||||
* The algorithm follows Knuth, 4.5.1.
|
||||
*
|
||||
* @param fraction the fraction to add, must not be {@code null}
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws IllegalArgumentException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the resulting numerator or denominator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public Fraction add(final Fraction fraction) {
|
||||
return addSub(fraction, true /* add */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts the value of another fraction from the value of this one,
|
||||
* returning the result in reduced form.
|
||||
*
|
||||
* @param fraction the fraction to subtract, must not be {@code null}
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws IllegalArgumentException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the resulting numerator or denominator
|
||||
* cannot be represented in an {@code int}.
|
||||
*/
|
||||
public Fraction subtract(final Fraction fraction) {
|
||||
return addSub(fraction, false /* subtract */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement add and subtract using algorithm described in Knuth 4.5.1.
|
||||
*
|
||||
* @param fraction the fraction to subtract, must not be {@code null}
|
||||
* @param isAdd true to add, false to subtract
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws IllegalArgumentException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the resulting numerator or denominator
|
||||
* cannot be represented in an {@code int}.
|
||||
*/
|
||||
private Fraction addSub(final Fraction fraction, final boolean isAdd) {
|
||||
Objects.requireNonNull(fraction, "fraction");
|
||||
// zero is identity for addition.
|
||||
if (numerator == 0) {
|
||||
return isAdd ? fraction : fraction.negate();
|
||||
}
|
||||
if (fraction.numerator == 0) {
|
||||
return this;
|
||||
}
|
||||
// if denominators are randomly distributed, d1 will be 1 about 61%
|
||||
// of the time.
|
||||
final int d1 = greatestCommonDivisor(denominator, fraction.denominator);
|
||||
if (d1 == 1) {
|
||||
// result is ( (u*v' +/- u'v) / u'v')
|
||||
final int uvp = mulAndCheck(numerator, fraction.denominator);
|
||||
final int upv = mulAndCheck(fraction.numerator, denominator);
|
||||
return new Fraction(isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv), mulPosAndCheck(denominator,
|
||||
fraction.denominator));
|
||||
}
|
||||
// the quantity 't' requires 65 bits of precision; see knuth 4.5.1
|
||||
// exercise 7. we're going to use a BigInteger.
|
||||
// t = u(v'/d1) +/- v(u'/d1)
|
||||
final BigInteger uvp = BigInteger.valueOf(numerator).multiply(BigInteger.valueOf(fraction.denominator / d1));
|
||||
final BigInteger upv = BigInteger.valueOf(fraction.numerator).multiply(BigInteger.valueOf(denominator / d1));
|
||||
final BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
|
||||
// but d2 doesn't need extra precision because
|
||||
// d2 = gcd(t,d1) = gcd(t mod d1, d1)
|
||||
final int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
|
||||
final int d2 = tmodd1 == 0 ? d1 : greatestCommonDivisor(tmodd1, d1);
|
||||
|
||||
// result is (t/d2) / (u'/d1)(v'/d2)
|
||||
final BigInteger w = t.divide(BigInteger.valueOf(d2));
|
||||
if (w.bitLength() > 31) {
|
||||
throw new ArithmeticException("overflow: numerator too large after multiply");
|
||||
}
|
||||
return new Fraction(w.intValue(), mulPosAndCheck(denominator / d1, fraction.denominator / d2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the value of this fraction by another, returning the
|
||||
* result in reduced form.
|
||||
*
|
||||
* @param fraction the fraction to multiply by, must not be {@code null}
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws NullPointerException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the resulting numerator or denominator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public Fraction multiplyBy(final Fraction fraction) {
|
||||
Objects.requireNonNull(fraction, "fraction");
|
||||
if (numerator == 0 || fraction.numerator == 0) {
|
||||
return ZERO;
|
||||
}
|
||||
// knuth 4.5.1
|
||||
// make sure we don't overflow unless the result *must* overflow.
|
||||
final int d1 = greatestCommonDivisor(numerator, fraction.denominator);
|
||||
final int d2 = greatestCommonDivisor(fraction.numerator, denominator);
|
||||
return getReducedFraction(mulAndCheck(numerator / d1, fraction.numerator / d2),
|
||||
mulPosAndCheck(denominator / d2, fraction.denominator / d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide the value of this fraction by another.
|
||||
*
|
||||
* @param fraction the fraction to divide by, must not be {@code null}
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws NullPointerException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the fraction to divide by is zero
|
||||
* @throws ArithmeticException if the resulting numerator or denominator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public Fraction divideBy(final Fraction fraction) {
|
||||
Objects.requireNonNull(fraction, "fraction");
|
||||
if (fraction.numerator == 0) {
|
||||
throw new ArithmeticException("The fraction to divide by must not be zero");
|
||||
}
|
||||
return multiplyBy(fraction.invert());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this fraction to another object to test if they are equal..
|
||||
*
|
||||
* <p>To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.</p>
|
||||
*
|
||||
* @param obj the reference object with which to compare
|
||||
* @return {@code true} if this object is equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Fraction)) {
|
||||
return false;
|
||||
}
|
||||
final Fraction other = (Fraction) obj;
|
||||
return getNumerator() == other.getNumerator() && getDenominator() == other.getDenominator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hashCode for the fraction.
|
||||
*
|
||||
* @return a hash code value for this object
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (hashCode == 0) {
|
||||
// hash code update should be atomic.
|
||||
hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to another based on size.
|
||||
*
|
||||
* <p>Note: this class has a natural ordering that is inconsistent
|
||||
* with equals, because, for example, equals treats 1/2 and 2/4 as
|
||||
* different, whereas compareTo treats them as equal.
|
||||
*
|
||||
* @param other the object to compare to
|
||||
* @return -1 if this is less, 0 if equal, +1 if greater
|
||||
* @throws ClassCastException if the object is not a {@link Fraction}
|
||||
* @throws NullPointerException if the object is {@code null}
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final Fraction other) {
|
||||
if (this == other) {
|
||||
return 0;
|
||||
}
|
||||
if (numerator == other.numerator && denominator == other.denominator) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// otherwise see which is less
|
||||
final long first = (long) numerator * (long) other.denominator;
|
||||
final long second = (long) other.numerator * (long) denominator;
|
||||
return Long.compare(first, second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@link String}.
|
||||
*
|
||||
* <p>The format used is '<i>numerator</i>/<i>denominator</i>' always.
|
||||
*
|
||||
* @return a {@link String} form of the fraction
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (toString == null) {
|
||||
toString = getNumerator() + "/" + getDenominator();
|
||||
}
|
||||
return toString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a proper {@link String} in the format X Y/Z.
|
||||
*
|
||||
* <p>The format used in '<i>wholeNumber</i> <i>numerator</i>/<i>denominator</i>'.
|
||||
* If the whole number is zero it will be omitted. If the numerator is zero,
|
||||
* only the whole number is returned.</p>
|
||||
*
|
||||
* @return a {@link String} form of the fraction
|
||||
*/
|
||||
public String toProperString() {
|
||||
if (toProperString == null) {
|
||||
if (numerator == 0) {
|
||||
toProperString = "0";
|
||||
} else if (numerator == denominator) {
|
||||
toProperString = "1";
|
||||
} else if (numerator == -1 * denominator) {
|
||||
toProperString = "-1";
|
||||
} else if ((numerator > 0 ? -numerator : numerator) < -denominator) {
|
||||
// note that we do the magnitude comparison test above with
|
||||
// NEGATIVE (not positive) numbers, since negative numbers
|
||||
// have a larger range. otherwise numerator==Integer.MIN_VALUE
|
||||
// is handled incorrectly.
|
||||
final int properNumerator = getProperNumerator();
|
||||
if (properNumerator == 0) {
|
||||
toProperString = Integer.toString(getProperWhole());
|
||||
} else {
|
||||
toProperString = getProperWhole() + " " + properNumerator + "/" + getDenominator();
|
||||
}
|
||||
} else {
|
||||
toProperString = getNumerator() + "/" + getDenominator();
|
||||
}
|
||||
}
|
||||
return toProperString;
|
||||
}
|
||||
}
|
252
src/main/java/ch/usi/inf/sdm/sdm04/math/IEEE754rUtils.java
Normal file
252
src/main/java/ch/usi/inf/sdm/sdm04/math/IEEE754rUtils.java
Normal file
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ch.usi.inf.sdm.sdm04.math;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Provides IEEE-754r variants of NumberUtils methods.
|
||||
*
|
||||
* <p>See: <a href="https://en.wikipedia.org/wiki/IEEE_754r">https://en.wikipedia.org/wiki/IEEE_754r</a></p>
|
||||
*
|
||||
* @since 2.4
|
||||
*/
|
||||
public class IEEE754rUtils {
|
||||
|
||||
/**
|
||||
* Returns the minimum value in an array.
|
||||
*
|
||||
* @param array an array, must not be null or empty
|
||||
* @return the minimum value in the array
|
||||
* @throws NullPointerException if {@code array} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code array} is empty
|
||||
* @since 3.4 Changed signature from min(double[]) to min(double...)
|
||||
*/
|
||||
public static double min(final double... array) {
|
||||
Objects.requireNonNull(array, "array");
|
||||
Validate.isTrue(array.length != 0, "Array cannot be empty.");
|
||||
|
||||
// Finds and returns min
|
||||
double min = array[0];
|
||||
for (int i = 1; i < array.length; i++) {
|
||||
min = min(array[i], min);
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum value in an array.
|
||||
*
|
||||
* @param array an array, must not be null or empty
|
||||
* @return the minimum value in the array
|
||||
* @throws NullPointerException if {@code array} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code array} is empty
|
||||
* @since 3.4 Changed signature from min(float[]) to min(float...)
|
||||
*/
|
||||
public static float min(final float... array) {
|
||||
Objects.requireNonNull(array, "array");
|
||||
Validate.isTrue(array.length != 0, "Array cannot be empty.");
|
||||
|
||||
// Finds and returns min
|
||||
float min = array[0];
|
||||
for (int i = 1; i < array.length; i++) {
|
||||
min = min(array[i], min);
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum of three {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @param c value 3
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static double min(final double a, final double b, final double c) {
|
||||
return min(min(a, b), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum of two {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static double min(final double a, final double b) {
|
||||
if (Double.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Double.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum of three {@code float} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @param c value 3
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static float min(final float a, final float b, final float c) {
|
||||
return min(min(a, b), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum of two {@code float} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static float min(final float a, final float b) {
|
||||
if (Float.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Float.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum value in an array.
|
||||
*
|
||||
* @param array an array, must not be null or empty
|
||||
* @return the minimum value in the array
|
||||
* @throws NullPointerException if {@code array} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code array} is empty
|
||||
* @since 3.4 Changed signature from max(double[]) to max(double...)
|
||||
*/
|
||||
public static double max(final double... array) {
|
||||
Objects.requireNonNull(array, "array");
|
||||
Validate.isTrue(array.length != 0, "Array cannot be empty.");
|
||||
|
||||
// Finds and returns max
|
||||
double max = array[0];
|
||||
for (int j = 1; j < array.length; j++) {
|
||||
max = max(array[j], max);
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum value in an array.
|
||||
*
|
||||
* @param array an array, must not be null or empty
|
||||
* @return the minimum value in the array
|
||||
* @throws NullPointerException if {@code array} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code array} is empty
|
||||
* @since 3.4 Changed signature from max(float[]) to max(float...)
|
||||
*/
|
||||
public static float max(final float... array) {
|
||||
Objects.requireNonNull(array, "array");
|
||||
Validate.isTrue(array.length != 0, "Array cannot be empty.");
|
||||
|
||||
// Finds and returns max
|
||||
float max = array[0];
|
||||
for (int j = 1; j < array.length; j++) {
|
||||
max = max(array[j], max);
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum of three {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @param c value 3
|
||||
* @return the largest of the values
|
||||
*/
|
||||
public static double max(final double a, final double b, final double c) {
|
||||
return max(max(a, b), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum of two {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @return the largest of the values
|
||||
*/
|
||||
public static double max(final double a, final double b) {
|
||||
if (Double.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Double.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
return Math.max(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum of three {@code float} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @param c value 3
|
||||
* @return the largest of the values
|
||||
*/
|
||||
public static float max(final float a, final float b, final float c) {
|
||||
return max(max(a, b), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum of two {@code float} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @return the largest of the values
|
||||
*/
|
||||
public static float max(final float a, final float b) {
|
||||
if (Float.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Float.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
return Math.max(a, b);
|
||||
}
|
||||
|
||||
}
|
611
src/main/java/ch/usi/inf/sdm/sdm04/util/FluentBitSet.java
Normal file
611
src/main/java/ch/usi/inf/sdm/sdm04/util/FluentBitSet.java
Normal file
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ch.usi.inf.sdm.sdm04.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.BitSet;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* A fluent {@link BitSet} with additional operations.
|
||||
* <p>
|
||||
* Originally from Apache Commons VFS with more added to act as a fluent replacement for {@link BitSet}.
|
||||
* </p>
|
||||
*
|
||||
* @since 3.13.0
|
||||
*/
|
||||
public final class FluentBitSet implements Cloneable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Working BitSet.
|
||||
*/
|
||||
private final BitSet bitSet;
|
||||
|
||||
/**
|
||||
* Creates a new bit set. All bits are initially {@code false}.
|
||||
*/
|
||||
public FluentBitSet() {
|
||||
this(new BitSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance for the given bit set.
|
||||
*
|
||||
* @param set The bit set to wrap.
|
||||
*/
|
||||
public FluentBitSet(final BitSet set) {
|
||||
this.bitSet = Objects.requireNonNull(set, "set");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a bit set whose initial size is large enough to explicitly represent bits with indices in the range {@code 0}
|
||||
* through {@code nbits-1}. All bits are initially {@code false}.
|
||||
*
|
||||
* @param nbits the initial size of the bit set.
|
||||
* @throws NegativeArraySizeException if the specified initial size is negative.
|
||||
*/
|
||||
public FluentBitSet(final int nbits) {
|
||||
this(new BitSet(nbits));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical <b>AND</b> of this target bit set with the argument bit set. This bit set is modified so that each
|
||||
* bit in it has the value {@code true} if and only if it both initially had the value {@code true} and the
|
||||
* corresponding bit in the bit set argument also had the value {@code true}.
|
||||
*
|
||||
* @param set a bit set.
|
||||
* @return this.
|
||||
*/
|
||||
public FluentBitSet and(final BitSet set) {
|
||||
bitSet.and(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical <b>AND</b> of this target bit set with the argument bit set. This bit set is modified so that each
|
||||
* bit in it has the value {@code true} if and only if it both initially had the value {@code true} and the
|
||||
* corresponding bit in the bit set argument also had the value {@code true}.
|
||||
*
|
||||
* @param set a bit set.
|
||||
* @return this.
|
||||
*/
|
||||
public FluentBitSet and(final FluentBitSet set) {
|
||||
bitSet.and(set.bitSet);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all of the bits in this {@link BitSet} whose corresponding bit is set in the specified {@link BitSet}.
|
||||
*
|
||||
* @param set the {@link BitSet} with which to mask this {@link BitSet}.
|
||||
* @return this.
|
||||
*/
|
||||
public FluentBitSet andNot(final BitSet set) {
|
||||
bitSet.andNot(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all of the bits in this {@link BitSet} whose corresponding bit is set in the specified {@link BitSet}.
|
||||
*
|
||||
* @param set the {@link BitSet} with which to mask this {@link BitSet}.
|
||||
* @return this.
|
||||
*/
|
||||
public FluentBitSet andNot(final FluentBitSet set) {
|
||||
this.bitSet.andNot(set.bitSet);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the wrapped bit set.
|
||||
*
|
||||
* @return the wrapped bit set.
|
||||
*/
|
||||
public BitSet bitSet() {
|
||||
return bitSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bits set to {@code true} in this {@link BitSet}.
|
||||
*
|
||||
* @return the number of bits set to {@code true} in this {@link BitSet}.
|
||||
*/
|
||||
public int cardinality() {
|
||||
return bitSet.cardinality();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all of the bits in this BitSet to {@code false}.
|
||||
*
|
||||
* @return this.
|
||||
*/
|
||||
public FluentBitSet clear() {
|
||||
bitSet.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits specified by the indexes to {@code false}.
|
||||
*
|
||||
* @param bitIndexArray the index of the bit to be cleared.
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if the specified index is negative.
|
||||
*/
|
||||
public FluentBitSet clear(final int... bitIndexArray) {
|
||||
for (final int e : bitIndexArray) {
|
||||
this.bitSet.clear(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit specified by the index to {@code false}.
|
||||
*
|
||||
* @param bitIndex the index of the bit to be cleared.
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if the specified index is negative.
|
||||
*/
|
||||
public FluentBitSet clear(final int bitIndex) {
|
||||
bitSet.clear(bitIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to
|
||||
* {@code false}.
|
||||
*
|
||||
* @param fromIndex index of the first bit to be cleared.
|
||||
* @param toIndex index after the last bit to be cleared.
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
|
||||
* {@code fromIndex} is larger than {@code toIndex}.
|
||||
*/
|
||||
public FluentBitSet clear(final int fromIndex, final int toIndex) {
|
||||
bitSet.clear(fromIndex, toIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cloning this {@link BitSet} produces a new {@link BitSet} that is equal to it. The clone of the bit set is another
|
||||
* bit set that has exactly the same bits set to {@code true} as this bit set.
|
||||
*
|
||||
* @return a clone of this bit set
|
||||
* @see #size()
|
||||
*/
|
||||
@Override
|
||||
public Object clone() {
|
||||
return new FluentBitSet((BitSet) bitSet.clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof FluentBitSet)) {
|
||||
return false;
|
||||
}
|
||||
final FluentBitSet other = (FluentBitSet) obj;
|
||||
return Objects.equals(bitSet, other.bitSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit at the specified index to the complement of its current value.
|
||||
*
|
||||
* @param bitIndex the index of the bit to flip.
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if the specified index is negative.
|
||||
*/
|
||||
public FluentBitSet flip(final int bitIndex) {
|
||||
bitSet.flip(bitIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets each bit from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to the
|
||||
* complement of its current value.
|
||||
*
|
||||
* @param fromIndex index of the first bit to flip.
|
||||
* @param toIndex index after the last bit to flip.
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
|
||||
* {@code fromIndex} is larger than {@code toIndex}.
|
||||
*/
|
||||
public FluentBitSet flip(final int fromIndex, final int toIndex) {
|
||||
bitSet.flip(fromIndex, toIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the bit with the specified index. The value is {@code true} if the bit with the index
|
||||
* {@code bitIndex} is currently set in this {@link BitSet}; otherwise, the result is {@code false}.
|
||||
*
|
||||
* @param bitIndex the bit index.
|
||||
* @return the value of the bit with the specified index.
|
||||
* @throws IndexOutOfBoundsException if the specified index is negative.
|
||||
*/
|
||||
public boolean get(final int bitIndex) {
|
||||
return bitSet.get(bitIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link BitSet} composed of bits from this {@link BitSet} from {@code fromIndex} (inclusive) to
|
||||
* {@code toIndex} (exclusive).
|
||||
*
|
||||
* @param fromIndex index of the first bit to include.
|
||||
* @param toIndex index after the last bit to include.
|
||||
* @return a new {@link BitSet} from a range of this {@link BitSet}.
|
||||
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
|
||||
* {@code fromIndex} is larger than {@code toIndex}.
|
||||
*/
|
||||
public FluentBitSet get(final int fromIndex, final int toIndex) {
|
||||
return new FluentBitSet(bitSet.get(fromIndex, toIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return bitSet.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified {@link BitSet} has any bits set to {@code true} that are also set to {@code true} in
|
||||
* this {@link BitSet}.
|
||||
*
|
||||
* @param set {@link BitSet} to intersect with.
|
||||
* @return boolean indicating whether this {@link BitSet} intersects the specified {@link BitSet}.
|
||||
*/
|
||||
public boolean intersects(final BitSet set) {
|
||||
return bitSet.intersects(set);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified {@link BitSet} has any bits set to {@code true} that are also set to {@code true} in
|
||||
* this {@link BitSet}.
|
||||
*
|
||||
* @param set {@link BitSet} to intersect with.
|
||||
* @return boolean indicating whether this {@link BitSet} intersects the specified {@link BitSet}.
|
||||
*/
|
||||
public boolean intersects(final FluentBitSet set) {
|
||||
return bitSet.intersects(set.bitSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this {@link BitSet} contains no bits that are set to {@code true}.
|
||||
*
|
||||
* @return boolean indicating whether this {@link BitSet} is empty.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return bitSet.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "logical size" of this {@link BitSet}: the index of the highest set bit in the {@link BitSet} plus one.
|
||||
* Returns zero if the {@link BitSet} contains no set bits.
|
||||
*
|
||||
* @return the logical size of this {@link BitSet}.
|
||||
*/
|
||||
public int length() {
|
||||
return bitSet.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first bit that is set to {@code false} that occurs on or after the specified starting index.
|
||||
*
|
||||
* @param fromIndex the index to start checking from (inclusive).
|
||||
* @return the index of the next clear bit.
|
||||
* @throws IndexOutOfBoundsException if the specified index is negative.
|
||||
*/
|
||||
public int nextClearBit(final int fromIndex) {
|
||||
return bitSet.nextClearBit(fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first bit that is set to {@code true} that occurs on or after the specified starting index.
|
||||
* If no such bit exists then {@code -1} is returned.
|
||||
* <p>
|
||||
* To iterate over the {@code true} bits in a {@link BitSet}, use the following loop:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
|
||||
* // operate on index i here
|
||||
* if (i == Integer.MAX_VALUE) {
|
||||
* break; // or (i+1) would overflow
|
||||
* }
|
||||
* }}
|
||||
* </pre>
|
||||
*
|
||||
* @param fromIndex the index to start checking from (inclusive).
|
||||
* @return the index of the next set bit, or {@code -1} if there is no such bit.
|
||||
* @throws IndexOutOfBoundsException if the specified index is negative.
|
||||
*/
|
||||
public int nextSetBit(final int fromIndex) {
|
||||
return bitSet.nextSetBit(fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical <b>OR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it
|
||||
* has the value {@code true} if and only if it either already had the value {@code true} or the corresponding bit in
|
||||
* the bit set argument has the value {@code true}.
|
||||
*
|
||||
* @param set a bit set.
|
||||
* @return this.
|
||||
*/
|
||||
public FluentBitSet or(final BitSet set) {
|
||||
bitSet.or(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical <b>OR</b> of this bit set with the bit set arguments. This bit set is modified so that a bit in it
|
||||
* has the value {@code true} if and only if it either already had the value {@code true} or the corresponding bit in
|
||||
* the bit set argument has the value {@code true}.
|
||||
*
|
||||
* @param set a bit set.
|
||||
* @return this.
|
||||
*/
|
||||
public FluentBitSet or(final FluentBitSet... set) {
|
||||
for (final FluentBitSet e : set) {
|
||||
this.bitSet.or(e.bitSet);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical <b>OR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it
|
||||
* has the value {@code true} if and only if it either already had the value {@code true} or the corresponding bit in
|
||||
* the bit set argument has the value {@code true}.
|
||||
*
|
||||
* @param set a bit set.
|
||||
* @return this.
|
||||
*/
|
||||
public FluentBitSet or(final FluentBitSet set) {
|
||||
this.bitSet.or(set.bitSet);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the nearest bit that is set to {@code false} that occurs on or before the specified starting
|
||||
* index. If no such bit exists, or if {@code -1} is given as the starting index, then {@code -1} is returned.
|
||||
*
|
||||
* @param fromIndex the index to start checking from (inclusive).
|
||||
* @return the index of the previous clear bit, or {@code -1} if there is no such bit.
|
||||
* @throws IndexOutOfBoundsException if the specified index is less than {@code -1}.
|
||||
*/
|
||||
public int previousClearBit(final int fromIndex) {
|
||||
return bitSet.previousClearBit(fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the nearest bit that is set to {@code true} that occurs on or before the specified starting
|
||||
* index. If no such bit exists, or if {@code -1} is given as the starting index, then {@code -1} is returned.
|
||||
*
|
||||
* <p>
|
||||
* To iterate over the {@code true} bits in a {@link BitSet}, use the following loop:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
|
||||
* // operate on index i here
|
||||
* }}
|
||||
* </pre>
|
||||
*
|
||||
* @param fromIndex the index to start checking from (inclusive)
|
||||
* @return the index of the previous set bit, or {@code -1} if there is no such bit
|
||||
* @throws IndexOutOfBoundsException if the specified index is less than {@code -1}
|
||||
*/
|
||||
public int previousSetBit(final int fromIndex) {
|
||||
return bitSet.previousSetBit(fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit at the specified indexes to {@code true}.
|
||||
*
|
||||
* @param bitIndexArray a bit index array.
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if the specified index is negative.
|
||||
*/
|
||||
public FluentBitSet set(final int... bitIndexArray) {
|
||||
for (final int e : bitIndexArray) {
|
||||
bitSet.set(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit at the specified index to {@code true}.
|
||||
*
|
||||
* @param bitIndex a bit index
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if the specified index is negative
|
||||
*/
|
||||
public FluentBitSet set(final int bitIndex) {
|
||||
bitSet.set(bitIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit at the specified index to the specified value.
|
||||
*
|
||||
* @param bitIndex a bit index.
|
||||
* @param value a boolean value to set.
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if the specified index is negative.
|
||||
*/
|
||||
|
||||
public FluentBitSet set(final int bitIndex, final boolean value) {
|
||||
bitSet.set(bitIndex, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to
|
||||
* {@code true}.
|
||||
*
|
||||
* @param fromIndex index of the first bit to be set.
|
||||
* @param toIndex index after the last bit to be set.
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
|
||||
* {@code fromIndex} is larger than {@code toIndex}.
|
||||
*/
|
||||
public FluentBitSet set(final int fromIndex, final int toIndex) {
|
||||
bitSet.set(fromIndex, toIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to the
|
||||
* specified value.
|
||||
*
|
||||
* @param fromIndex index of the first bit to be set.
|
||||
* @param toIndex index after the last bit to be set.
|
||||
* @param value value to set the selected bits to.
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
|
||||
* {@code fromIndex} is larger than {@code toIndex}.
|
||||
*/
|
||||
public FluentBitSet set(final int fromIndex, final int toIndex, final boolean value) {
|
||||
bitSet.set(fromIndex, toIndex, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to
|
||||
* {@code true}.
|
||||
*
|
||||
* @param fromIndex index of the first bit to be set
|
||||
* @param toIndex index of the last bit to be set
|
||||
* @return this.
|
||||
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
|
||||
* {@code fromIndex} is larger than {@code toIndex}
|
||||
*/
|
||||
public FluentBitSet setInclusive(final int fromIndex, final int toIndex) {
|
||||
bitSet.set(fromIndex, toIndex + 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bits of space actually in use by this {@link BitSet} to represent bit values. The maximum
|
||||
* element in the set is the size - 1st element.
|
||||
*
|
||||
* @return the number of bits currently in this bit set.
|
||||
*/
|
||||
public int size() {
|
||||
return bitSet.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream of indices for which this {@link BitSet} contains a bit in the set state. The indices are returned
|
||||
* in order, from lowest to highest. The size of the stream is the number of bits in the set state, equal to the value
|
||||
* returned by the {@link #cardinality()} method.
|
||||
*
|
||||
* <p>
|
||||
* The bit set must remain constant during the execution of the terminal stream operation. Otherwise, the result of the
|
||||
* terminal stream operation is undefined.
|
||||
* </p>
|
||||
*
|
||||
* @return a stream of integers representing set indices.
|
||||
* @since 1.8
|
||||
*/
|
||||
public IntStream stream() {
|
||||
return bitSet.stream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new byte array containing all the bits in this bit set.
|
||||
*
|
||||
* <p>
|
||||
* More precisely, if:
|
||||
* </p>
|
||||
* <ol>
|
||||
* <li>{@code byte[] bytes = s.toByteArray();}</li>
|
||||
* <li>then {@code bytes.length == (s.length()+7)/8} and</li>
|
||||
* <li>{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}</li>
|
||||
* <li>for all {@code n < 8 * bytes.length}.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @return a byte array containing a little-endian representation of all the bits in this bit set
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
return bitSet.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new byte array containing all the bits in this bit set.
|
||||
*
|
||||
* <p>
|
||||
* More precisely, if:
|
||||
* </p>
|
||||
* <ol>
|
||||
* <li>{@code long[] longs = s.toLongArray();}</li>
|
||||
* <li>then {@code longs.length == (s.length()+63)/64} and</li>
|
||||
* <li>{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}</li>
|
||||
* <li>for all {@code n < 64 * longs.length}.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @return a byte array containing a little-endian representation of all the bits in this bit set
|
||||
*/
|
||||
public long[] toLongArray() {
|
||||
return bitSet.toLongArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return bitSet.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical <b>XOR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it
|
||||
* has the value {@code true} if and only if one of the following statements holds:
|
||||
* <ul>
|
||||
* <li>The bit initially has the value {@code true}, and the corresponding bit in the argument has the value
|
||||
* {@code false}.
|
||||
* <li>The bit initially has the value {@code false}, and the corresponding bit in the argument has the value
|
||||
* {@code true}.
|
||||
* </ul>
|
||||
*
|
||||
* @param set a bit set
|
||||
* @return this.
|
||||
*/
|
||||
public FluentBitSet xor(final BitSet set) {
|
||||
bitSet.xor(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical <b>XOR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it
|
||||
* has the value {@code true} if and only if one of the following statements holds:
|
||||
* <ul>
|
||||
* <li>The bit initially has the value {@code true}, and the corresponding bit in the argument has the value
|
||||
* {@code false}.
|
||||
* <li>The bit initially has the value {@code false}, and the corresponding bit in the argument has the value
|
||||
* {@code true}.
|
||||
* </ul>
|
||||
*
|
||||
* @param set a bit set
|
||||
* @return this.
|
||||
*/
|
||||
public FluentBitSet xor(final FluentBitSet set) {
|
||||
bitSet.xor(set.bitSet);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
382
src/test/java/ch/usi/inf/sdm/sdm04/CharRangeTest.java
Normal file
382
src/test/java/ch/usi/inf/sdm/sdm04/CharRangeTest.java
Normal file
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package ch.usi.inf.sdm.sdm04;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Unit tests {@link CharRange}.
|
||||
*/
|
||||
public class CharRangeTest {
|
||||
|
||||
@Test
|
||||
public void testClass() {
|
||||
// class changed to non-public in 3.0
|
||||
assertFalse(Modifier.isPublic(CharRange.class.getModifiers()));
|
||||
assertTrue(Modifier.isFinal(CharRange.class.getModifiers()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorAccessors_is() {
|
||||
final CharRange rangea = CharRange.is('a');
|
||||
assertEquals('a', rangea.getStart());
|
||||
assertEquals('a', rangea.getEnd());
|
||||
assertFalse(rangea.isNegated());
|
||||
assertEquals("a", rangea.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorAccessors_isNot() {
|
||||
final CharRange rangea = CharRange.isNot('a');
|
||||
assertEquals('a', rangea.getStart());
|
||||
assertEquals('a', rangea.getEnd());
|
||||
assertTrue(rangea.isNegated());
|
||||
assertEquals("^a", rangea.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorAccessors_isIn_Same() {
|
||||
final CharRange rangea = CharRange.isIn('a', 'a');
|
||||
assertEquals('a', rangea.getStart());
|
||||
assertEquals('a', rangea.getEnd());
|
||||
assertFalse(rangea.isNegated());
|
||||
assertEquals("a", rangea.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorAccessors_isIn_Normal() {
|
||||
final CharRange rangea = CharRange.isIn('a', 'e');
|
||||
assertEquals('a', rangea.getStart());
|
||||
assertEquals('e', rangea.getEnd());
|
||||
assertFalse(rangea.isNegated());
|
||||
assertEquals("a-e", rangea.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorAccessors_isIn_Reversed() {
|
||||
final CharRange rangea = CharRange.isIn('e', 'a');
|
||||
assertEquals('a', rangea.getStart());
|
||||
assertEquals('e', rangea.getEnd());
|
||||
assertFalse(rangea.isNegated());
|
||||
assertEquals("a-e", rangea.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorAccessors_isNotIn_Same() {
|
||||
final CharRange rangea = CharRange.isNotIn('a', 'a');
|
||||
assertEquals('a', rangea.getStart());
|
||||
assertEquals('a', rangea.getEnd());
|
||||
assertTrue(rangea.isNegated());
|
||||
assertEquals("^a", rangea.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorAccessors_isNotIn_Normal() {
|
||||
final CharRange rangea = CharRange.isNotIn('a', 'e');
|
||||
assertEquals('a', rangea.getStart());
|
||||
assertEquals('e', rangea.getEnd());
|
||||
assertTrue(rangea.isNegated());
|
||||
assertEquals("^a-e", rangea.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorAccessors_isNotIn_Reversed() {
|
||||
final CharRange rangea = CharRange.isNotIn('e', 'a');
|
||||
assertEquals('a', rangea.getStart());
|
||||
assertEquals('e', rangea.getEnd());
|
||||
assertTrue(rangea.isNegated());
|
||||
assertEquals("^a-e", rangea.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals_Object() {
|
||||
final CharRange rangea = CharRange.is('a');
|
||||
final CharRange rangeae = CharRange.isIn('a', 'e');
|
||||
final CharRange rangenotbf = CharRange.isIn('b', 'f');
|
||||
|
||||
assertNotEquals(null, rangea);
|
||||
|
||||
assertEquals(rangea, rangea);
|
||||
assertEquals(rangea, CharRange.is('a'));
|
||||
assertEquals(rangeae, rangeae);
|
||||
assertEquals(rangeae, CharRange.isIn('a', 'e'));
|
||||
assertEquals(rangenotbf, rangenotbf);
|
||||
assertEquals(rangenotbf, CharRange.isIn('b', 'f'));
|
||||
|
||||
assertNotEquals(rangea, rangeae);
|
||||
assertNotEquals(rangea, rangenotbf);
|
||||
assertNotEquals(rangeae, rangea);
|
||||
assertNotEquals(rangeae, rangenotbf);
|
||||
assertNotEquals(rangenotbf, rangea);
|
||||
assertNotEquals(rangenotbf, rangeae);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHashCode() {
|
||||
final CharRange rangea = CharRange.is('a');
|
||||
final CharRange rangeae = CharRange.isIn('a', 'e');
|
||||
final CharRange rangenotbf = CharRange.isIn('b', 'f');
|
||||
|
||||
assertEquals(rangea.hashCode(), rangea.hashCode());
|
||||
assertEquals(rangea.hashCode(), CharRange.is('a').hashCode());
|
||||
assertEquals(rangeae.hashCode(), rangeae.hashCode());
|
||||
assertEquals(rangeae.hashCode(), CharRange.isIn('a', 'e').hashCode());
|
||||
assertEquals(rangenotbf.hashCode(), rangenotbf.hashCode());
|
||||
assertEquals(rangenotbf.hashCode(), CharRange.isIn('b', 'f').hashCode());
|
||||
|
||||
assertNotEquals(rangea.hashCode(), rangeae.hashCode());
|
||||
assertNotEquals(rangea.hashCode(), rangenotbf.hashCode());
|
||||
assertNotEquals(rangeae.hashCode(), rangea.hashCode());
|
||||
assertNotEquals(rangeae.hashCode(), rangenotbf.hashCode());
|
||||
assertNotEquals(rangenotbf.hashCode(), rangea.hashCode());
|
||||
assertNotEquals(rangenotbf.hashCode(), rangeae.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContains_Char() {
|
||||
CharRange range = CharRange.is('c');
|
||||
assertFalse(range.contains('b'));
|
||||
assertTrue(range.contains('c'));
|
||||
assertFalse(range.contains('d'));
|
||||
assertFalse(range.contains('e'));
|
||||
|
||||
range = CharRange.isIn('c', 'd');
|
||||
assertFalse(range.contains('b'));
|
||||
assertTrue(range.contains('c'));
|
||||
assertTrue(range.contains('d'));
|
||||
assertFalse(range.contains('e'));
|
||||
|
||||
range = CharRange.isIn('d', 'c');
|
||||
assertFalse(range.contains('b'));
|
||||
assertTrue(range.contains('c'));
|
||||
assertTrue(range.contains('d'));
|
||||
assertFalse(range.contains('e'));
|
||||
|
||||
range = CharRange.isNotIn('c', 'd');
|
||||
assertTrue(range.contains('b'));
|
||||
assertFalse(range.contains('c'));
|
||||
assertFalse(range.contains('d'));
|
||||
assertTrue(range.contains('e'));
|
||||
assertTrue(range.contains((char) 0));
|
||||
assertTrue(range.contains(Character.MAX_VALUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContains_Charrange() {
|
||||
final CharRange a = CharRange.is('a');
|
||||
final CharRange b = CharRange.is('b');
|
||||
final CharRange c = CharRange.is('c');
|
||||
final CharRange c2 = CharRange.is('c');
|
||||
final CharRange d = CharRange.is('d');
|
||||
final CharRange e = CharRange.is('e');
|
||||
final CharRange cd = CharRange.isIn('c', 'd');
|
||||
final CharRange bd = CharRange.isIn('b', 'd');
|
||||
final CharRange bc = CharRange.isIn('b', 'c');
|
||||
final CharRange ab = CharRange.isIn('a', 'b');
|
||||
final CharRange de = CharRange.isIn('d', 'e');
|
||||
final CharRange ef = CharRange.isIn('e', 'f');
|
||||
final CharRange ae = CharRange.isIn('a', 'e');
|
||||
|
||||
// normal/normal
|
||||
assertFalse(c.contains(b));
|
||||
assertTrue(c.contains(c));
|
||||
assertTrue(c.contains(c2));
|
||||
assertFalse(c.contains(d));
|
||||
|
||||
assertFalse(c.contains(cd));
|
||||
assertFalse(c.contains(bd));
|
||||
assertFalse(c.contains(bc));
|
||||
assertFalse(c.contains(ab));
|
||||
assertFalse(c.contains(de));
|
||||
|
||||
assertTrue(cd.contains(c));
|
||||
assertTrue(bd.contains(c));
|
||||
assertTrue(bc.contains(c));
|
||||
assertFalse(ab.contains(c));
|
||||
assertFalse(de.contains(c));
|
||||
|
||||
assertTrue(ae.contains(b));
|
||||
assertTrue(ae.contains(ab));
|
||||
assertTrue(ae.contains(bc));
|
||||
assertTrue(ae.contains(cd));
|
||||
assertTrue(ae.contains(de));
|
||||
|
||||
final CharRange notb = CharRange.isNot('b');
|
||||
final CharRange notc = CharRange.isNot('c');
|
||||
final CharRange notd = CharRange.isNot('d');
|
||||
final CharRange notab = CharRange.isNotIn('a', 'b');
|
||||
final CharRange notbc = CharRange.isNotIn('b', 'c');
|
||||
final CharRange notbd = CharRange.isNotIn('b', 'd');
|
||||
final CharRange notcd = CharRange.isNotIn('c', 'd');
|
||||
final CharRange notde = CharRange.isNotIn('d', 'e');
|
||||
final CharRange notae = CharRange.isNotIn('a', 'e');
|
||||
final CharRange all = CharRange.isIn((char) 0, Character.MAX_VALUE);
|
||||
final CharRange allbutfirst = CharRange.isIn((char) 1, Character.MAX_VALUE);
|
||||
|
||||
// normal/negated
|
||||
assertFalse(c.contains(notc));
|
||||
assertFalse(c.contains(notbd));
|
||||
assertTrue(all.contains(notc));
|
||||
assertTrue(all.contains(notbd));
|
||||
assertFalse(allbutfirst.contains(notc));
|
||||
assertFalse(allbutfirst.contains(notbd));
|
||||
|
||||
// negated/normal
|
||||
assertTrue(notc.contains(a));
|
||||
assertTrue(notc.contains(b));
|
||||
assertFalse(notc.contains(c));
|
||||
assertTrue(notc.contains(d));
|
||||
assertTrue(notc.contains(e));
|
||||
|
||||
assertTrue(notc.contains(ab));
|
||||
assertFalse(notc.contains(bc));
|
||||
assertFalse(notc.contains(bd));
|
||||
assertFalse(notc.contains(cd));
|
||||
assertTrue(notc.contains(de));
|
||||
assertFalse(notc.contains(ae));
|
||||
assertFalse(notc.contains(all));
|
||||
assertFalse(notc.contains(allbutfirst));
|
||||
|
||||
assertTrue(notbd.contains(a));
|
||||
assertFalse(notbd.contains(b));
|
||||
assertFalse(notbd.contains(c));
|
||||
assertFalse(notbd.contains(d));
|
||||
assertTrue(notbd.contains(e));
|
||||
|
||||
assertTrue(notcd.contains(ab));
|
||||
assertFalse(notcd.contains(bc));
|
||||
assertFalse(notcd.contains(bd));
|
||||
assertFalse(notcd.contains(cd));
|
||||
assertFalse(notcd.contains(de));
|
||||
assertFalse(notcd.contains(ae));
|
||||
assertTrue(notcd.contains(ef));
|
||||
assertFalse(notcd.contains(all));
|
||||
assertFalse(notcd.contains(allbutfirst));
|
||||
|
||||
// negated/negated
|
||||
assertFalse(notc.contains(notb));
|
||||
assertTrue(notc.contains(notc));
|
||||
assertFalse(notc.contains(notd));
|
||||
|
||||
assertFalse(notc.contains(notab));
|
||||
assertTrue(notc.contains(notbc));
|
||||
assertTrue(notc.contains(notbd));
|
||||
assertTrue(notc.contains(notcd));
|
||||
assertFalse(notc.contains(notde));
|
||||
|
||||
assertFalse(notbd.contains(notb));
|
||||
assertFalse(notbd.contains(notc));
|
||||
assertFalse(notbd.contains(notd));
|
||||
|
||||
assertFalse(notbd.contains(notab));
|
||||
assertFalse(notbd.contains(notbc));
|
||||
assertTrue(notbd.contains(notbd));
|
||||
assertFalse(notbd.contains(notcd));
|
||||
assertFalse(notbd.contains(notde));
|
||||
assertTrue(notbd.contains(notae));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsNullArg() {
|
||||
final CharRange range = CharRange.is('a');
|
||||
final NullPointerException e = assertThrows(NullPointerException.class, () -> range.contains(null));
|
||||
assertEquals("range", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIterator() {
|
||||
final CharRange a = CharRange.is('a');
|
||||
final CharRange ad = CharRange.isIn('a', 'd');
|
||||
final CharRange nota = CharRange.isNot('a');
|
||||
final CharRange emptySet = CharRange.isNotIn((char) 0, Character.MAX_VALUE);
|
||||
final CharRange notFirst = CharRange.isNotIn((char) 1, Character.MAX_VALUE);
|
||||
final CharRange notLast = CharRange.isNotIn((char) 0, (char) (Character.MAX_VALUE - 1));
|
||||
|
||||
final Iterator<Character> aIt = a.iterator();
|
||||
assertNotNull(aIt);
|
||||
assertTrue(aIt.hasNext());
|
||||
assertEquals(Character.valueOf('a'), aIt.next());
|
||||
assertFalse(aIt.hasNext());
|
||||
|
||||
final Iterator<Character> adIt = ad.iterator();
|
||||
assertNotNull(adIt);
|
||||
assertTrue(adIt.hasNext());
|
||||
assertEquals(Character.valueOf('a'), adIt.next());
|
||||
assertEquals(Character.valueOf('b'), adIt.next());
|
||||
assertEquals(Character.valueOf('c'), adIt.next());
|
||||
assertEquals(Character.valueOf('d'), adIt.next());
|
||||
assertFalse(adIt.hasNext());
|
||||
|
||||
final Iterator<Character> notaIt = nota.iterator();
|
||||
assertNotNull(notaIt);
|
||||
assertTrue(notaIt.hasNext());
|
||||
while (notaIt.hasNext()) {
|
||||
final Character c = notaIt.next();
|
||||
assertNotEquals('a', c.charValue());
|
||||
}
|
||||
|
||||
final Iterator<Character> emptySetIt = emptySet.iterator();
|
||||
assertNotNull(emptySetIt);
|
||||
assertFalse(emptySetIt.hasNext());
|
||||
assertThrows(NoSuchElementException.class, emptySetIt::next);
|
||||
|
||||
final Iterator<Character> notFirstIt = notFirst.iterator();
|
||||
assertNotNull(notFirstIt);
|
||||
assertTrue(notFirstIt.hasNext());
|
||||
assertEquals(Character.valueOf((char) 0), notFirstIt.next());
|
||||
assertFalse(notFirstIt.hasNext());
|
||||
assertThrows(NoSuchElementException.class, notFirstIt::next);
|
||||
|
||||
final Iterator<Character> notLastIt = notLast.iterator();
|
||||
assertNotNull(notLastIt);
|
||||
assertTrue(notLastIt.hasNext());
|
||||
assertEquals(Character.valueOf(Character.MAX_VALUE), notLastIt.next());
|
||||
assertFalse(notLastIt.hasNext());
|
||||
assertThrows(NoSuchElementException.class, notLastIt::next);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialization() {
|
||||
CharRange range = CharRange.is('a');
|
||||
assertEquals(range, SerializationUtils.clone(range));
|
||||
range = CharRange.isIn('a', 'e');
|
||||
assertEquals(range, SerializationUtils.clone(range));
|
||||
range = CharRange.isNotIn('a', 'e');
|
||||
assertEquals(range, SerializationUtils.clone(range));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIteratorRemove() {
|
||||
final CharRange a = CharRange.is('a');
|
||||
final Iterator<Character> aIt = a.iterator();
|
||||
assertThrows(UnsupportedOperationException.class, aIt::remove);
|
||||
}
|
||||
}
|
1123
src/test/java/ch/usi/inf/sdm/sdm04/math/FractionTest.java
Normal file
1123
src/test/java/ch/usi/inf/sdm/sdm04/math/FractionTest.java
Normal file
File diff suppressed because it is too large
Load diff
104
src/test/java/ch/usi/inf/sdm/sdm04/math/IEEE754rUtilsTest.java
Normal file
104
src/test/java/ch/usi/inf/sdm/sdm04/math/IEEE754rUtilsTest.java
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ch.usi.inf.sdm.sdm04.math;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Unit tests {@link org.apache.commons.lang3.math.IEEE754rUtils}.
|
||||
*/
|
||||
public class IEEE754rUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testConstructorExists() {
|
||||
new IEEE754rUtils();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnforceExceptions() {
|
||||
assertThrows(
|
||||
NullPointerException.class,
|
||||
() -> IEEE754rUtils.min( (float[]) null),
|
||||
"IllegalArgumentException expected for null input");
|
||||
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
IEEE754rUtils::min,
|
||||
"IllegalArgumentException expected for empty input");
|
||||
|
||||
assertThrows(
|
||||
NullPointerException.class,
|
||||
() -> IEEE754rUtils.max( (float[]) null),
|
||||
"IllegalArgumentException expected for null input");
|
||||
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
IEEE754rUtils::max,
|
||||
"IllegalArgumentException expected for empty input");
|
||||
|
||||
assertThrows(
|
||||
NullPointerException.class,
|
||||
() -> IEEE754rUtils.min( (double[]) null),
|
||||
"IllegalArgumentException expected for null input");
|
||||
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
IEEE754rUtils::min,
|
||||
"IllegalArgumentException expected for empty input");
|
||||
|
||||
assertThrows(
|
||||
NullPointerException.class,
|
||||
() -> IEEE754rUtils.max( (double[]) null),
|
||||
"IllegalArgumentException expected for null input");
|
||||
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
IEEE754rUtils::max,
|
||||
"IllegalArgumentException expected for empty input");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLang381() {
|
||||
assertEquals(1.2, IEEE754rUtils.min(1.2, 2.5, Double.NaN), 0.01);
|
||||
assertEquals(2.5, IEEE754rUtils.max(1.2, 2.5, Double.NaN), 0.01);
|
||||
assertTrue(Double.isNaN(IEEE754rUtils.max(Double.NaN, Double.NaN, Double.NaN)));
|
||||
assertEquals(1.2f, IEEE754rUtils.min(1.2f, 2.5f, Float.NaN), 0.01);
|
||||
assertEquals(2.5f, IEEE754rUtils.max(1.2f, 2.5f, Float.NaN), 0.01);
|
||||
assertTrue(Float.isNaN(IEEE754rUtils.max(Float.NaN, Float.NaN, Float.NaN)));
|
||||
|
||||
final double[] a = { 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
|
||||
assertEquals(42.0, IEEE754rUtils.max(a), 0.01);
|
||||
assertEquals(1.2, IEEE754rUtils.min(a), 0.01);
|
||||
|
||||
final double[] b = { Double.NaN, 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
|
||||
assertEquals(42.0, IEEE754rUtils.max(b), 0.01);
|
||||
assertEquals(1.2, IEEE754rUtils.min(b), 0.01);
|
||||
|
||||
final float[] aF = { 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
|
||||
assertEquals(1.2f, IEEE754rUtils.min(aF), 0.01);
|
||||
assertEquals(42.0f, IEEE754rUtils.max(aF), 0.01);
|
||||
|
||||
final float[] bF = { Float.NaN, 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
|
||||
assertEquals(1.2f, IEEE754rUtils.min(bF), 0.01);
|
||||
assertEquals(42.0f, IEEE754rUtils.max(bF), 0.01);
|
||||
}
|
||||
|
||||
}
|
1827
src/test/java/ch/usi/inf/sdm/sdm04/util/FluentBitSetTest.java
Normal file
1827
src/test/java/ch/usi/inf/sdm/sdm04/util/FluentBitSetTest.java
Normal file
File diff suppressed because it is too large
Load diff
Reference in a new issue