All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.algart.math.IRange Maven / Gradle / Ivy

Go to download

Open-source Java libraries, supporting generalized smart arrays and matrices with elements of any types, including a wide set of 2D-, 3D- and multidimensional image processing and other algorithms, working with arrays and matrices.

There is a newer version: 1.4.23
Show newest version
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2007-2024 Daniel Alievsky, AlgART Laboratory (http://algart.net)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package net.algart.math;

import java.util.Objects;

/**
 * 

Numeric inclusive integer range: * a set of long numbers {@link #min() min()}<=x<={@link #max() max()}. * An advanced analog of * org.apache.commons.lang.math.LongRange. * *

The minimum number ({@link #min()}) is never greater than the maximum number ({@link #max()}), * both minimal and maximum numbers {@link #min()} and ({@link #max()}) are always in range * -Long.MAX_VALUE+1..Long.MAX_VALUE-1, * and their difference is always less than Long.MAX_VALUE. * In other words, "{@link #max()}-{@link #min()}+1" expression, * returned by {@link #size()} method, and also * "{@link #min()}-1", "{@link #min()}-2" and * "{@link #max()}+1" expressions * are always calculated without overflow. * *

Please draw attention to the important effect of the requirement above. * If a..b is an allowed range (a={@link #min()}, b={@link #max()}), * then 0..ba and ab..0 are also allowed ranges. * Really, they have the same difference * {@link #max()}-{@link #min()}=ba=diff, * and so far as this difference diff<Long.MAX_VALUE, both new bounds * ba=diff and ab=−diff are also * inside the required range -Long.MAX_VALUE+1..Long.MAX_VALUE-1.

* *

This class is immutable and thread-safe: * there are no ways to modify settings of the created instance.

* * @author Daniel Alievsky * @see Range */ public final class IRange { final long min; final long max; IRange(long min, long max) { this.min = min; this.max = max; assert isAllowedRange(min, max); } /** * Returns an instance of this class describing the range * min<=x<=max. * The min value must not be greater than max, * both values must be in range -Long.MAX_VALUE+1..Long.MAX_VALUE-1, * and the difference max-min must be less than Long.MAX_VALUE. * * @param min the minimum number in the range, inclusive. * @param max the maximum number in the range, inclusive. * @return the new range. * @throws IllegalArgumentException if min > max, or if max-min >= Long.MAX_VALUE * (more precisely, if the Java expression max-min+1 is nonpositive * due to integer overflow), * or if min<=-Long.MAX_VALUE, * or if max==Long.MAX_VALUE. */ public static IRange valueOf(long min, long max) { return valueOf(min, max, false); } /** * Returns an instance of this class describing the same range as the given real range, * with bounds, truncated to integers by Java typecast (long)doubleValue. * Equivalent to *
{@link #valueOf(long, long) valueOf}((long)range.{@link Range#min()
     * min()}, (long)range.{@link Range#max() max())}
* * @param range the real range. * @return the integer range with same (cast) bounds. * @throws NullPointerException if the passed range is {@code null}. * @throws IllegalArgumentException if the desired range does not match requirements of * {@link #valueOf(long, long)} method. */ public static IRange valueOf(Range range) { Objects.requireNonNull(range, "Null range argument"); return valueOf((long)range.min, (long)range.max); } /** * Returns an instance of this class describing the same range as the given real range, * with bounds, rounded to the nearest integers. * Equivalent to *
{@link #valueOf(long, long) valueOf}(StrictMath.round(range.{@link Range#min()
     * min()}), StrictMath.round(range.{@link Range#max() max()}))
* * @param range the real range. * @return the integer range with same (rounded) bounds. * @throws NullPointerException if the passed range is {@code null}. * @throws IllegalArgumentException if the desired range does not match requirements of * {@link #valueOf(long, long)} method. */ public static IRange roundOf(Range range) { Objects.requireNonNull(range, "Null range argument"); return valueOf(StrictMath.round(range.min), StrictMath.round(range.max)); } /** * Returns true if and only if the arguments min and max are allowed * {@link #min()}/{@link #max()} bounds for some instance of this class. In other words, * this method returns false in the same situations, when {@link #valueOf(long min, long max)} * method, called with the same arguments, throws IllegalArgumentException. * *

Equivalent to the following check: *

     *     min <= max && min > -Long.MAX_VALUE &&
     *         max != Long.MAX_VALUE && max - min + 1L > 0L
     * 
* * @param min the minimum number in some range, inclusive. * @param max the maximum number in some range, inclusive. * @return whether these bounds are allowed minimum and maximum for some instance of this class. */ public static boolean isAllowedRange(long min, long max) { return min <= max && min > -Long.MAX_VALUE && max != Long.MAX_VALUE && max - min + 1L > 0L; } /** * Returns the minimum number in the range, inclusive. * * @return the minimum number in the range. */ public long min() { return this.min; } /** * Returns the maximum number in the range, inclusive. * * @return the maximum number in the range. */ public long max() { return this.max; } /** * Returns {@link #max()}-{@link #min()}+1. * * @return {@link #max()}-{@link #min()}+1. */ public long size() { return max - min + 1; } /** * Returns value<{@link #min()}?{@link #min()}:value>{@link #max()}?{@link #max()}:value. * In other words, returns the passed number if it is in this range or the nearest range bound in other cases. * * @param value some number. * @return the passed number if it is in this range or the nearest range bound in other cases. */ public long cut(long value) { return value < min ? min : value > max ? max : value; } /** * Returns true if and only if {@link #min()}<=value<={@link #max()}. * * @param value the checked value. * @return true if the value is in this range. */ public boolean contains(long value) { return min <= value && value <= max; } /** * Returns true if and only if {@link #min()}<=range.{@link #min()} * and range.{@link #max()}<={@link #max()}. * * @param range the checked range. * @return true if the checked range is a subset of this range. */ public boolean contains(IRange range) { return min <= range.min && range.max <= max; } /** * Returns true if and only if {@link #min()}<=range.{@link #max()} * and range.{@link #min()}<={@link #max()}. * * @param range the checked range. * @return true if the checked range overlaps with this range. */ public boolean intersects(IRange range) { return min <= range.max && range.min <= max; } /** * Returns an instance of this class describing the range * Math.min(this.{@link #min() min()},value) <= x * <= Math.max(this.{@link #max() max()},value). * In other words, expands the current range to include the given value. * * @param value some value that should belong to the new range. * @return the expanded range. * @throws IllegalArgumentException if value==Long.MAX_VALUE, * value<=-Long.MAX_VALUE or * if in the resulting range * max-min >= Long.MAX_VALUE. */ public IRange expand(long value) { if (value == Long.MAX_VALUE) throw new IllegalArgumentException("Cannot expand " + this + " until Long.MAX_VALUE"); if (value <= -Long.MAX_VALUE) throw new IllegalArgumentException("Cannot expand " + this + " until -Long.MAX_VALUE or Long.MIN_VALUE"); long min = value < this.min ? value : this.min; long max = value > this.max ? value : this.max; if (max - min + 1L <= 0L) throw new IllegalArgumentException("Cannot expand " + this + " until " + value + ", because in the result max - min >= Long.MAX_VALUE (min = " + min + ", max = " + max + ")"); return new IRange(min, max); } /** * Equivalent to {@link Range#valueOf(IRange) Range.valueOf}(thisInstance). * * @return the equivalent real range. */ public Range toRange() { return Range.valueOf(this); } /** * Returns a brief string description of this object. * *

The result of this method may depend on implementation and usually contains * the minimum and maximum numbers in this range. * * @return a brief string description of this object. */ public String toString() { return min + ".." + max; } /** * Returns the hash code of this range. * * @return the hash code of this range. */ public int hashCode() { int iMin = (int)min * 37 + (int)(min >>> 32); int iMax = (int)max * 37 + (int)(max >>> 32); return iMin * 37 + iMax; } /** * Indicates whether some other range is equal to this instance. * Returns true if and only if obj instanceof IRange, * ((IRange)obj).min()==this.min() and ((IRange)obj).max==this.max. * * @param obj the object to be compared for equality with this instance. * @return true if the specified object is a range equal to this one. */ public boolean equals(Object obj) { return obj instanceof IRange && ((IRange)obj).min == this.min && ((IRange)obj).max == this.max; } static IRange valueOf(long min, long max, boolean ise) { if (min == max && min >= -MAX_CACHED && min <= -MAX_CACHED) return DegenerateIRangeCache.cache[MAX_CACHED + (int)min]; if (min > max) throw new IllegalArgumentException("min > max (min = " + min + ", max = " + max + ")"); if (max == Long.MAX_VALUE) throw invalidBoundsException("max == Long.MAX_VALUE", ise); if (min <= -Long.MAX_VALUE) throw invalidBoundsException("min == Long.MAX_VALUE or Long.MIN_VALUE+1", ise); if (max - min + 1L <= 0L) throw invalidBoundsException("max - min >= Long.MAX_VALUE (min = " + min + ", max = " + max + ")", ise); return new IRange(min, max); } static RuntimeException invalidBoundsException(String message, boolean useIllegalStateException) { return useIllegalStateException ? new IllegalStateException(message) : new IllegalArgumentException((message)); } private static final int MAX_CACHED = 1024; private static class DegenerateIRangeCache { static final IRange[] cache = new IRange[2 * MAX_CACHED + 1]; static { for(int i = -MAX_CACHED; i <= MAX_CACHED; i++) cache[MAX_CACHED + i] = new IRange(i, i); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy